remove GenericVectorTests from rsp (#17366)
[mono-project.git] / mono / metadata / sre-encode.c
blob86e2c2923e96b364d8aa8c2915cc56c43b29d276
1 /**
2 * \file
3 * Routines for encoding SRE builders into a
4 * MonoDynamicImage and generating tokens.
5 *
6 *
7 * Author:
8 * Paolo Molaro (lupus@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Copyright 2011 Rodrigo Kumpera
13 * Copyright 2016 Microsoft
15 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
17 #include <config.h>
18 #include <glib.h>
20 #include "mono/metadata/dynamic-image-internals.h"
21 #include "mono/metadata/dynamic-stream-internals.h"
22 #include "mono/metadata/object-internals.h"
23 #include "mono/metadata/reflection-internals.h"
24 #include "mono/metadata/sre-internals.h"
25 #include "mono/metadata/tabledefs.h"
26 #include "mono/metadata/tokentype.h"
27 #include "mono/utils/checked-build.h"
28 #include "icall-decl.h"
30 typedef struct {
31 char *p;
32 char *buf;
33 char *end;
34 } SigBuffer;
36 static guint32 create_typespec (MonoDynamicImage *assembly, MonoType *type);
37 static void encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf);
38 static guint32 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type);
40 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
41 static guint32
42 mono_image_add_stream_data (MonoDynamicStream *stream, const char *data, guint32 len)
44 return mono_dynstream_add_data (stream, data, len);
46 #endif
48 static void
49 alloc_table (MonoDynamicTable *table, guint nrows)
51 mono_dynimage_alloc_table (table, nrows);
54 static void
55 sigbuffer_init (SigBuffer *buf, int size)
57 MONO_REQ_GC_NEUTRAL_MODE;
59 buf->buf = (char *)g_malloc (size);
60 buf->p = buf->buf;
61 buf->end = buf->buf + size;
64 static void
65 sigbuffer_make_room (SigBuffer *buf, int size)
67 MONO_REQ_GC_NEUTRAL_MODE;
69 if (buf->end - buf->p < size) {
70 int new_size = buf->end - buf->buf + size + 32;
71 char *p = (char *)g_realloc (buf->buf, new_size);
72 size = buf->p - buf->buf;
73 buf->buf = p;
74 buf->p = p + size;
75 buf->end = buf->buf + new_size;
79 static void
80 sigbuffer_add_value (SigBuffer *buf, guint32 val)
82 MONO_REQ_GC_NEUTRAL_MODE;
84 sigbuffer_make_room (buf, 6);
85 mono_metadata_encode_value (val, buf->p, &buf->p);
88 static void
89 sigbuffer_add_byte (SigBuffer *buf, guint8 val)
91 MONO_REQ_GC_NEUTRAL_MODE;
93 sigbuffer_make_room (buf, 1);
94 buf->p [0] = val;
95 buf->p++;
98 static void
99 sigbuffer_add_mem (SigBuffer *buf, char *p, guint32 size)
101 MONO_REQ_GC_NEUTRAL_MODE;
103 sigbuffer_make_room (buf, size);
104 memcpy (buf->p, p, size);
105 buf->p += size;
108 static void
109 sigbuffer_free (SigBuffer *buf)
111 MONO_REQ_GC_NEUTRAL_MODE;
113 g_free (buf->buf);
116 static guint32
117 sigbuffer_add_to_blob_cached (MonoDynamicImage *assembly, SigBuffer *buf)
119 MONO_REQ_GC_NEUTRAL_MODE;
121 char blob_size [8];
122 char *b = blob_size;
123 guint32 size = buf->p - buf->buf;
124 /* store length */
125 g_assert (size <= (buf->end - buf->buf));
126 mono_metadata_encode_value (size, b, &b);
127 return mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, buf->buf, size);
131 static void
132 encode_generic_class (MonoDynamicImage *assembly, MonoGenericClass *gclass, SigBuffer *buf)
134 MONO_REQ_GC_NEUTRAL_MODE;
136 int i;
137 MonoGenericInst *class_inst;
138 MonoClass *klass;
140 g_assert (gclass);
142 class_inst = gclass->context.class_inst;
144 sigbuffer_add_value (buf, MONO_TYPE_GENERICINST);
145 klass = gclass->container_class;
146 sigbuffer_add_value (buf, m_class_get_byval_arg (klass)->type);
147 sigbuffer_add_value (buf, mono_dynimage_encode_typedef_or_ref_full (assembly, m_class_get_byval_arg (klass), FALSE));
149 sigbuffer_add_value (buf, class_inst->type_argc);
150 for (i = 0; i < class_inst->type_argc; ++i)
151 encode_type (assembly, class_inst->type_argv [i], buf);
155 static void
156 encode_type (MonoDynamicImage *assembly, MonoType *type, SigBuffer *buf)
158 MONO_REQ_GC_NEUTRAL_MODE;
160 if (!type) {
161 g_assert_not_reached ();
162 return;
165 if (type->byref)
166 sigbuffer_add_value (buf, MONO_TYPE_BYREF);
168 switch (type->type){
169 case MONO_TYPE_VOID:
170 case MONO_TYPE_BOOLEAN:
171 case MONO_TYPE_CHAR:
172 case MONO_TYPE_I1:
173 case MONO_TYPE_U1:
174 case MONO_TYPE_I2:
175 case MONO_TYPE_U2:
176 case MONO_TYPE_I4:
177 case MONO_TYPE_U4:
178 case MONO_TYPE_I8:
179 case MONO_TYPE_U8:
180 case MONO_TYPE_R4:
181 case MONO_TYPE_R8:
182 case MONO_TYPE_I:
183 case MONO_TYPE_U:
184 case MONO_TYPE_STRING:
185 case MONO_TYPE_OBJECT:
186 case MONO_TYPE_TYPEDBYREF:
187 sigbuffer_add_value (buf, type->type);
188 break;
189 case MONO_TYPE_PTR:
190 sigbuffer_add_value (buf, type->type);
191 encode_type (assembly, type->data.type, buf);
192 break;
193 case MONO_TYPE_SZARRAY:
194 sigbuffer_add_value (buf, type->type);
195 encode_type (assembly, m_class_get_byval_arg (type->data.klass), buf);
196 break;
197 case MONO_TYPE_VALUETYPE:
198 case MONO_TYPE_CLASS: {
199 MonoClass *k = mono_class_from_mono_type_internal (type);
201 if (mono_class_is_gtd (k)) {
202 MonoGenericClass *gclass = mono_metadata_lookup_generic_class (k, mono_class_get_generic_container (k)->context.class_inst, TRUE);
203 encode_generic_class (assembly, gclass, buf);
204 } else {
206 * Make sure we use the correct type.
208 sigbuffer_add_value (buf, m_class_get_byval_arg (k)->type);
210 * ensure only non-byref gets passed to mono_image_typedef_or_ref(),
211 * otherwise two typerefs could point to the same type, leading to
212 * verification errors.
214 sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, m_class_get_byval_arg (k)));
216 break;
218 case MONO_TYPE_ARRAY:
219 sigbuffer_add_value (buf, type->type);
220 encode_type (assembly, m_class_get_byval_arg (type->data.array->eklass), buf);
221 sigbuffer_add_value (buf, type->data.array->rank);
222 sigbuffer_add_value (buf, 0); /* FIXME: set to 0 for now */
223 sigbuffer_add_value (buf, 0);
224 break;
225 case MONO_TYPE_GENERICINST:
226 encode_generic_class (assembly, type->data.generic_class, buf);
227 break;
228 case MONO_TYPE_VAR:
229 case MONO_TYPE_MVAR:
230 sigbuffer_add_value (buf, type->type);
231 sigbuffer_add_value (buf, mono_type_get_generic_param_num (type));
232 break;
233 default:
234 g_error ("need to encode type %x", type->type);
238 static void
239 encode_reflection_type (MonoDynamicImage *assembly, MonoReflectionTypeHandle type, SigBuffer *buf, MonoError *error)
241 MONO_REQ_GC_UNSAFE_MODE;
243 error_init (error);
245 if (MONO_HANDLE_IS_NULL (type)) {
246 sigbuffer_add_value (buf, MONO_TYPE_VOID);
247 return;
250 MonoType *t = mono_reflection_type_handle_mono_type (type, error);
251 return_if_nok (error);
252 encode_type (assembly, t, buf);
255 static void
256 encode_reflection_type_raw (MonoDynamicImage *assembly, MonoReflectionType* type_raw, SigBuffer *buf, MonoError *error)
258 HANDLE_FUNCTION_ENTER (); /* FIXME callers of encode_reflection_type_raw should use handles */
259 error_init (error);
260 MONO_HANDLE_DCL (MonoReflectionType, type);
261 encode_reflection_type (assembly, type, buf, error);
262 HANDLE_FUNCTION_RETURN ();
266 static void
267 encode_custom_modifiers (MonoDynamicImage *assembly, MonoArrayHandle modreq, MonoArrayHandle modopt, SigBuffer *buf, MonoError *error)
269 HANDLE_FUNCTION_ENTER ();
270 MONO_REQ_GC_UNSAFE_MODE;
272 int i;
274 error_init (error);
276 /* Have to follow .NET Framework behavior here. For an IL type spec like:
277 * int32 modreq(A) modreq(B) modopt(C) modopt(D)
279 * we emit:
280 * cmod_opt [encoding of D] cmod_opt [encoding of C] cmod_req [encoding of B] cmod_req [encoding of A] I4.
282 * Even though the reflection API specifies required and optional
283 * modifiers in separate arrays, the .NET Framework creates a typespec
284 * as above: required mods first, then optional. (And so we emit the
285 * optional ones first, then required).
288 if (!MONO_HANDLE_IS_NULL (modopt)) {
289 int count = mono_array_handle_length (modopt);
290 g_assert (count > 0);
291 for (i = count - 1; i >= 0 ; --i) {
292 MonoType *mod = mono_type_array_get_and_resolve (modopt, i, error);
293 goto_if_nok (error, leave);
294 sigbuffer_add_byte (buf, MONO_TYPE_CMOD_OPT);
295 sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, mod));
298 if (!MONO_HANDLE_IS_NULL (modreq)) {
299 int count = mono_array_handle_length (modreq);
300 g_assert (count > 0);
301 for (i = count - 1; i >= 0 ; --i) {
302 MonoType *mod = mono_type_array_get_and_resolve (modreq, i, error);
303 goto_if_nok (error, leave);
304 sigbuffer_add_byte (buf, MONO_TYPE_CMOD_REQD);
305 sigbuffer_add_value (buf, mono_image_typedef_or_ref (assembly, mod));
309 leave:
310 HANDLE_FUNCTION_RETURN ();
313 static void
314 encode_custom_modifiers_raw (MonoDynamicImage *assembly, MonoArray *modreq_raw, MonoArray *modopt_raw, SigBuffer *buf, MonoError *error)
316 HANDLE_FUNCTION_ENTER (); /* FIXME callers of encode_custom_modifiers_raw should use handles */
317 error_init (error);
318 MONO_HANDLE_DCL (MonoArray, modreq);
319 MONO_HANDLE_DCL (MonoArray, modopt);
320 encode_custom_modifiers (assembly, modreq, modopt, buf, error);
321 HANDLE_FUNCTION_RETURN ();
325 #ifndef DISABLE_REFLECTION_EMIT
326 guint32
327 mono_dynimage_encode_method_signature (MonoDynamicImage *assembly, MonoMethodSignature *sig)
329 MONO_REQ_GC_UNSAFE_MODE;
331 SigBuffer buf;
332 int i;
333 guint32 nparams = sig->param_count;
334 guint32 idx;
336 if (!assembly->save)
337 return 0;
339 sigbuffer_init (&buf, 32);
341 * FIXME: vararg, explicit_this, differenc call_conv values...
343 idx = sig->call_convention;
344 if (sig->hasthis)
345 idx |= 0x20; /* hasthis */
346 if (sig->generic_param_count)
347 idx |= 0x10; /* generic */
348 sigbuffer_add_byte (&buf, idx);
349 if (sig->generic_param_count)
350 sigbuffer_add_value (&buf, sig->generic_param_count);
351 sigbuffer_add_value (&buf, nparams);
352 encode_type (assembly, sig->ret, &buf);
353 for (i = 0; i < nparams; ++i) {
354 if (i == sig->sentinelpos)
355 sigbuffer_add_byte (&buf, MONO_TYPE_SENTINEL);
356 encode_type (assembly, sig->params [i], &buf);
358 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
359 sigbuffer_free (&buf);
360 return idx;
362 #else /* DISABLE_REFLECTION_EMIT */
363 guint32
364 mono_dynimage_encode_method_signature (MonoDynamicImage *assembly, MonoMethodSignature *sig)
366 g_assert_not_reached ();
367 return 0;
369 #endif
371 guint32
372 mono_dynimage_encode_method_builder_signature (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb, MonoError *error)
374 MONO_REQ_GC_UNSAFE_MODE;
376 error_init (error);
379 * FIXME: reuse code from method_encode_signature().
381 SigBuffer buf;
382 int i;
383 guint32 nparams = mb->parameters ? mono_array_length_internal (mb->parameters): 0;
384 guint32 ngparams = mb->generic_params ? mono_array_length_internal (mb->generic_params): 0;
385 guint32 notypes = mb->opt_types ? mono_array_length_internal (mb->opt_types): 0;
386 guint32 idx;
388 sigbuffer_init (&buf, 32);
389 /* LAMESPEC: all the call conv spec is foobared */
390 idx = mb->call_conv & 0x60; /* has-this, explicit-this */
391 if (mb->call_conv & 2)
392 idx |= 0x5; /* vararg */
393 if (!(mb->attrs & METHOD_ATTRIBUTE_STATIC))
394 idx |= 0x20; /* hasthis */
395 if (ngparams)
396 idx |= 0x10; /* generic */
397 sigbuffer_add_byte (&buf, idx);
398 if (ngparams)
399 sigbuffer_add_value (&buf, ngparams);
400 sigbuffer_add_value (&buf, nparams + notypes);
401 encode_custom_modifiers_raw (assembly, mb->return_modreq, mb->return_modopt, &buf, error);
402 goto_if_nok (error, leave);
403 encode_reflection_type_raw (assembly, mb->rtype, &buf, error);
404 goto_if_nok (error, leave);
405 for (i = 0; i < nparams; ++i) {
406 MonoArray *modreq = NULL;
407 MonoArray *modopt = NULL;
408 MonoReflectionType *pt;
410 if (mb->param_modreq && (i < mono_array_length_internal (mb->param_modreq)))
411 modreq = mono_array_get_internal (mb->param_modreq, MonoArray*, i);
412 if (mb->param_modopt && (i < mono_array_length_internal (mb->param_modopt)))
413 modopt = mono_array_get_internal (mb->param_modopt, MonoArray*, i);
414 encode_custom_modifiers_raw (assembly, modreq, modopt, &buf, error);
415 goto_if_nok (error, leave);
416 pt = mono_array_get_internal (mb->parameters, MonoReflectionType*, i);
417 encode_reflection_type_raw (assembly, pt, &buf, error);
418 goto_if_nok (error, leave);
420 if (notypes)
421 sigbuffer_add_byte (&buf, MONO_TYPE_SENTINEL);
422 for (i = 0; i < notypes; ++i) {
423 MonoReflectionType *pt;
425 pt = mono_array_get_internal (mb->opt_types, MonoReflectionType*, i);
426 encode_reflection_type_raw (assembly, pt, &buf, error);
427 goto_if_nok (error, leave);
430 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
431 leave:
432 sigbuffer_free (&buf);
433 return idx;
436 guint32
437 mono_dynimage_encode_locals (MonoDynamicImage *assembly, MonoReflectionILGen *ilgen, MonoError *error)
439 MONO_REQ_GC_UNSAFE_MODE;
441 error_init (error);
443 MonoDynamicTable *table;
444 guint32 *values;
445 guint32 idx, sig_idx;
446 guint nl = mono_array_length_internal (ilgen->locals);
447 SigBuffer buf;
448 int i;
450 sigbuffer_init (&buf, 32);
451 sigbuffer_add_value (&buf, 0x07);
452 sigbuffer_add_value (&buf, nl);
453 for (i = 0; i < nl; ++i) {
454 MonoReflectionLocalBuilder *lb = mono_array_get_internal (ilgen->locals, MonoReflectionLocalBuilder*, i);
456 if (lb->is_pinned)
457 sigbuffer_add_value (&buf, MONO_TYPE_PINNED);
459 encode_reflection_type_raw (assembly, (MonoReflectionType*)lb->type, &buf, error);
460 if (!is_ok (error)) {
461 sigbuffer_free (&buf);
462 return 0;
465 sig_idx = sigbuffer_add_to_blob_cached (assembly, &buf);
466 sigbuffer_free (&buf);
468 if (assembly->standalonesig_cache == NULL)
469 assembly->standalonesig_cache = g_hash_table_new (NULL, NULL);
470 idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->standalonesig_cache, GUINT_TO_POINTER (sig_idx)));
471 if (idx)
472 return idx;
474 table = &assembly->tables [MONO_TABLE_STANDALONESIG];
475 idx = table->next_idx ++;
476 table->rows ++;
477 alloc_table (table, table->rows);
478 values = table->values + idx * MONO_STAND_ALONE_SIGNATURE_SIZE;
480 values [MONO_STAND_ALONE_SIGNATURE] = sig_idx;
482 g_hash_table_insert (assembly->standalonesig_cache, GUINT_TO_POINTER (sig_idx), GUINT_TO_POINTER (idx));
484 return idx;
489 * Copy len * nelem bytes from val to dest, swapping bytes to LE if necessary.
490 * dest may be misaligned.
492 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
493 static void
494 swap_with_size (char *dest, const char* val, int len, int nelem) {
495 MONO_REQ_GC_NEUTRAL_MODE;
496 int elem;
498 for (elem = 0; elem < nelem; ++elem) {
499 switch (len) {
500 case 1:
501 *dest = *val;
502 break;
503 case 2:
504 dest [0] = val [1];
505 dest [1] = val [0];
506 break;
507 case 4:
508 dest [0] = val [3];
509 dest [1] = val [2];
510 dest [2] = val [1];
511 dest [3] = val [0];
512 break;
513 case 8:
514 dest [0] = val [7];
515 dest [1] = val [6];
516 dest [2] = val [5];
517 dest [3] = val [4];
518 dest [4] = val [3];
519 dest [5] = val [2];
520 dest [6] = val [1];
521 dest [7] = val [0];
522 break;
523 default:
524 g_assert_not_reached ();
526 dest += len;
527 val += len;
530 #endif
533 guint32
534 mono_dynimage_encode_constant (MonoDynamicImage *assembly, MonoObject *val, MonoTypeEnum *ret_type)
536 MONO_REQ_GC_UNSAFE_MODE;
538 char blob_size [64];
539 char *b = blob_size;
540 gpointer box_val;
541 char* buf;
542 guint32 idx = 0, len = 0, dummy = 0;
544 buf = (char *)g_malloc (64);
545 if (!val) {
546 *ret_type = MONO_TYPE_CLASS;
547 len = 4;
548 box_val = &dummy;
549 } else {
550 box_val = mono_object_get_data (val);
551 *ret_type = m_class_get_byval_arg (val->vtable->klass)->type;
553 handle_enum:
554 switch (*ret_type) {
555 case MONO_TYPE_BOOLEAN:
556 case MONO_TYPE_U1:
557 case MONO_TYPE_I1:
558 len = 1;
559 break;
560 case MONO_TYPE_CHAR:
561 case MONO_TYPE_U2:
562 case MONO_TYPE_I2:
563 len = 2;
564 break;
565 case MONO_TYPE_U4:
566 case MONO_TYPE_I4:
567 case MONO_TYPE_R4:
568 len = 4;
569 break;
570 case MONO_TYPE_U8:
571 case MONO_TYPE_I8:
572 len = 8;
573 break;
574 case MONO_TYPE_R8:
575 len = 8;
576 break;
577 case MONO_TYPE_VALUETYPE: {
578 MonoClass *klass = val->vtable->klass;
580 if (m_class_is_enumtype (klass)) {
581 *ret_type = mono_class_enum_basetype_internal (klass)->type;
582 goto handle_enum;
583 } else if (mono_is_corlib_image (m_class_get_image (klass)) && strcmp (m_class_get_name_space (klass), "System") == 0 && strcmp (m_class_get_name (klass), "DateTime") == 0) {
584 len = 8;
585 } else
586 g_error ("we can't encode valuetypes, we should have never reached this line");
587 break;
589 case MONO_TYPE_CLASS:
590 break;
591 case MONO_TYPE_STRING: {
592 MonoString *str = (MonoString*)val;
593 /* there is no signature */
594 len = str->length * 2;
595 mono_metadata_encode_value (len, b, &b);
596 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
598 char *swapped = g_malloc (2 * mono_string_length_internal (str));
599 const char *p = (const char*)mono_string_chars_internal (str);
601 swap_with_size (swapped, p, 2, mono_string_length_internal (str));
602 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, swapped, len);
603 g_free (swapped);
605 #else
606 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, mono_string_chars_internal (str), len);
607 #endif
609 g_free (buf);
610 return idx;
612 case MONO_TYPE_GENERICINST:
613 *ret_type = m_class_get_byval_arg (mono_class_get_generic_class (val->vtable->klass)->container_class)->type;
614 goto handle_enum;
615 default:
616 g_error ("we don't encode constant type 0x%02x yet", *ret_type);
619 /* there is no signature */
620 mono_metadata_encode_value (len, b, &b);
621 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
622 idx = mono_image_add_stream_data (&assembly->blob, blob_size, b-blob_size);
623 swap_with_size (blob_size, box_val, len, 1);
624 mono_image_add_stream_data (&assembly->blob, blob_size, len);
625 #else
626 idx = mono_dynamic_image_add_to_blob_cached (assembly, blob_size, b-blob_size, box_val, len);
627 #endif
629 g_free (buf);
630 return idx;
633 guint32
634 mono_dynimage_encode_field_signature (MonoDynamicImage *assembly, MonoReflectionFieldBuilder *fb, MonoError *error)
636 MONO_REQ_GC_UNSAFE_MODE;
638 error_init (error);
640 SigBuffer buf;
641 guint32 idx;
642 guint32 typespec = 0;
643 MonoType *type;
644 MonoClass *klass;
646 type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
647 return_val_if_nok (error, 0);
648 klass = mono_class_from_mono_type_internal (type);
650 sigbuffer_init (&buf, 32);
652 sigbuffer_add_value (&buf, 0x06);
653 encode_custom_modifiers_raw (assembly, fb->modreq, fb->modopt, &buf, error);
654 goto_if_nok (error, fail);
655 /* encode custom attributes before the type */
657 if (mono_class_is_gtd (klass))
658 typespec = create_typespec (assembly, type);
660 if (typespec) {
661 MonoGenericClass *gclass;
662 gclass = mono_metadata_lookup_generic_class (klass, mono_class_get_generic_container (klass)->context.class_inst, TRUE);
663 encode_generic_class (assembly, gclass, &buf);
664 } else {
665 encode_type (assembly, type, &buf);
667 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
668 sigbuffer_free (&buf);
669 return idx;
670 fail:
671 sigbuffer_free (&buf);
672 return 0;
675 #ifndef DISABLE_REFLECTION_EMIT
676 /*field_image is the image to which the eventual custom mods have been encoded against*/
677 guint32
678 mono_dynimage_encode_fieldref_signature (MonoDynamicImage *assembly, MonoImage *field_image, MonoType *type)
680 MONO_REQ_GC_NEUTRAL_MODE;
682 SigBuffer buf;
683 guint32 idx, i, token;
685 if (!assembly->save)
686 return 0;
688 sigbuffer_init (&buf, 32);
690 sigbuffer_add_value (&buf, 0x06);
691 /* encode custom attributes before the type */
692 if (type->has_cmods) {
693 MonoCustomModContainer *cmods = mono_type_get_cmods (type);
694 for (i = 0; i < cmods->count; ++i) {
695 if (field_image) {
696 ERROR_DECL (error);
697 MonoClass *klass = mono_class_get_checked (field_image, cmods->modifiers [i].token, error);
698 g_assert (is_ok (error)); /* FIXME don't swallow the error */
700 token = mono_image_typedef_or_ref (assembly, m_class_get_byval_arg (klass));
701 } else {
702 token = cmods->modifiers [i].token;
705 if (cmods->modifiers [i].required)
706 sigbuffer_add_byte (&buf, MONO_TYPE_CMOD_REQD);
707 else
708 sigbuffer_add_byte (&buf, MONO_TYPE_CMOD_OPT);
710 sigbuffer_add_value (&buf, token);
713 encode_type (assembly, type, &buf);
714 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
715 sigbuffer_free (&buf);
716 return idx;
718 #else /* DISABLE_REFLECTION_EMIT */
719 guint32
720 mono_dynimage_encode_fieldref_signature (MonoDynamicImage *assembly, MonoImage *field_image, MonoType *type)
722 g_assert_not_reached ();
723 return 0;
725 #endif /* DISABLE_REFLECTION_EMIT */
727 static guint32
728 create_typespec (MonoDynamicImage *assembly, MonoType *type)
730 MONO_REQ_GC_NEUTRAL_MODE;
732 MonoDynamicTable *table;
733 guint32 *values;
734 guint32 token;
735 SigBuffer buf;
737 if ((token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typespec, type))))
738 return token;
740 sigbuffer_init (&buf, 32);
741 switch (type->type) {
742 case MONO_TYPE_FNPTR:
743 case MONO_TYPE_PTR:
744 case MONO_TYPE_SZARRAY:
745 case MONO_TYPE_ARRAY:
746 case MONO_TYPE_VAR:
747 case MONO_TYPE_MVAR:
748 case MONO_TYPE_GENERICINST:
749 encode_type (assembly, type, &buf);
750 break;
751 case MONO_TYPE_CLASS:
752 case MONO_TYPE_VALUETYPE: {
753 MonoClass *k = mono_class_from_mono_type_internal (type);
754 if (!k || !mono_class_is_gtd (k)) {
755 sigbuffer_free (&buf);
756 return 0;
758 encode_type (assembly, type, &buf);
759 break;
761 default:
762 sigbuffer_free (&buf);
763 return 0;
766 table = &assembly->tables [MONO_TABLE_TYPESPEC];
767 if (assembly->save) {
768 token = sigbuffer_add_to_blob_cached (assembly, &buf);
769 alloc_table (table, table->rows + 1);
770 values = table->values + table->next_idx * MONO_TYPESPEC_SIZE;
771 values [MONO_TYPESPEC_SIGNATURE] = token;
773 sigbuffer_free (&buf);
775 token = MONO_TYPEDEFORREF_TYPESPEC | (table->next_idx << MONO_TYPEDEFORREF_BITS);
776 g_hash_table_insert (assembly->typespec, type, GUINT_TO_POINTER(token));
777 table->next_idx ++;
778 return token;
781 guint32
782 mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *type, gboolean try_typespec)
784 MONO_REQ_GC_UNSAFE_MODE;
785 HANDLE_FUNCTION_ENTER ();
787 MonoDynamicTable *table;
788 guint32 *values;
789 guint32 token, scope, enclosing;
790 MonoClass *klass;
792 /* if the type requires a typespec, we must try that first*/
793 if (try_typespec && (token = create_typespec (assembly, type)))
794 goto leave;
795 token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typeref, type));
796 if (token)
797 goto leave;
798 klass = mono_class_from_mono_type_internal (type);
800 MonoReflectionTypeBuilderHandle tb;
801 tb = MONO_HANDLE_CAST (MonoReflectionTypeBuilder, mono_class_get_ref_info (klass));
803 * If it's in the same module and not a generic type parameter:
805 if ((m_class_get_image (klass) == &assembly->image) && (type->type != MONO_TYPE_VAR) &&
806 (type->type != MONO_TYPE_MVAR)) {
807 token = MONO_TYPEDEFORREF_TYPEDEF | (MONO_HANDLE_GETVAL (tb, table_idx) << MONO_TYPEDEFORREF_BITS);
808 /* This function is called multiple times from sre and sre-save, so same object is okay */
809 mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, tb), MONO_DYN_IMAGE_TOK_SAME_OK);
810 goto leave;
813 if (m_class_get_nested_in (klass)) {
814 enclosing = mono_dynimage_encode_typedef_or_ref_full (assembly, m_class_get_byval_arg (m_class_get_nested_in (klass)), FALSE);
815 /* get the typeref idx of the enclosing type */
816 enclosing >>= MONO_TYPEDEFORREF_BITS;
817 scope = (enclosing << MONO_RESOLUTION_SCOPE_BITS) | MONO_RESOLUTION_SCOPE_TYPEREF;
818 } else {
819 scope = mono_reflection_resolution_scope_from_image (assembly, m_class_get_image (klass));
821 table = &assembly->tables [MONO_TABLE_TYPEREF];
822 if (assembly->save) {
823 alloc_table (table, table->rows + 1);
824 values = table->values + table->next_idx * MONO_TYPEREF_SIZE;
825 values [MONO_TYPEREF_SCOPE] = scope;
826 values [MONO_TYPEREF_NAME] = mono_dynstream_insert_string (&assembly->sheap, m_class_get_name (klass));
827 values [MONO_TYPEREF_NAMESPACE] = mono_dynstream_insert_string (&assembly->sheap, m_class_get_name_space (klass));
829 token = MONO_TYPEDEFORREF_TYPEREF | (table->next_idx << MONO_TYPEDEFORREF_BITS); /* typeref */
830 g_hash_table_insert (assembly->typeref, type, GUINT_TO_POINTER(token));
831 table->next_idx ++;
834 if (!MONO_HANDLE_IS_NULL (tb)) {
835 /* This function is called multiple times from sre and sre-save, so same object is okay */
836 mono_dynamic_image_register_token (assembly, token, MONO_HANDLE_CAST (MonoObject, tb), MONO_DYN_IMAGE_TOK_SAME_OK);
839 leave:
840 HANDLE_FUNCTION_RETURN_VAL (token);
844 * Despite the name, we handle also TypeSpec (with the above helper).
846 static guint32
847 mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
849 return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
852 guint32
853 mono_dynimage_encode_generic_method_sig (MonoDynamicImage *assembly, MonoGenericContext *context)
855 SigBuffer buf;
856 int i;
857 guint32 nparams = context->method_inst->type_argc;
858 guint32 idx;
860 if (!assembly->save)
861 return 0;
863 sigbuffer_init (&buf, 32);
865 * FIXME: vararg, explicit_this, differenc call_conv values...
867 sigbuffer_add_value (&buf, 0xa); /* FIXME FIXME FIXME */
868 sigbuffer_add_value (&buf, nparams);
870 for (i = 0; i < nparams; i++)
871 encode_type (assembly, context->method_inst->type_argv [i], &buf);
873 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
874 sigbuffer_free (&buf);
875 return idx;
878 #ifndef DISABLE_REFLECTION_EMIT
879 static gboolean
880 encode_sighelper_arg (MonoDynamicImage *assembly, int i, MonoArrayHandle helper_arguments, MonoArrayHandle helper_modreqs, MonoArrayHandle helper_modopts, SigBuffer* buf, MonoError *error)
882 HANDLE_FUNCTION_ENTER();
883 error_init (error);
884 MonoArrayHandle modreqs = MONO_HANDLE_NEW (MonoArray, NULL);
885 MonoArrayHandle modopts = MONO_HANDLE_NEW (MonoArray, NULL);
887 if (!MONO_HANDLE_IS_NULL (helper_modreqs) && (i < mono_array_handle_length (helper_modreqs)))
888 MONO_HANDLE_ARRAY_GETREF (modreqs, helper_modreqs, i);
889 if (!MONO_HANDLE_IS_NULL (helper_modopts) && (i < mono_array_handle_length (helper_modopts)))
890 MONO_HANDLE_ARRAY_GETREF (modopts, helper_modopts, i);
892 encode_custom_modifiers (assembly, modreqs, modopts, buf, error);
893 goto_if_nok (error, leave);
894 MonoReflectionTypeHandle pt;
895 pt = MONO_HANDLE_NEW (MonoReflectionType, NULL);
896 MONO_HANDLE_ARRAY_GETREF (pt, helper_arguments, i);
897 encode_reflection_type (assembly, pt, buf, error);
898 goto_if_nok (error, leave);
899 leave:
900 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
903 guint32
904 mono_dynimage_encode_reflection_sighelper (MonoDynamicImage *assembly, MonoReflectionSigHelperHandle helper, MonoError *error)
906 SigBuffer buf;
907 guint32 nargs;
908 guint32 i, idx;
910 error_init (error);
912 if (!assembly->save)
913 return 0;
915 /* FIXME: this means SignatureHelper.SignatureHelpType.HELPER_METHOD */
916 g_assert (MONO_HANDLE_GETVAL (helper, type) == 2);
918 MonoArrayHandle arguments = MONO_HANDLE_NEW_GET (MonoArray, helper, arguments);
919 if (!MONO_HANDLE_IS_NULL (arguments))
920 nargs = mono_array_handle_length (arguments);
921 else
922 nargs = 0;
924 sigbuffer_init (&buf, 32);
926 /* Encode calling convention */
927 /* Change Any to Standard */
928 if ((MONO_HANDLE_GETVAL (helper, call_conv) & 0x03) == 0x03)
929 MONO_HANDLE_SETVAL (helper, call_conv, guint32, 0x01);
930 /* explicit_this implies has_this */
931 if (MONO_HANDLE_GETVAL (helper, call_conv) & 0x40)
932 MONO_HANDLE_SETVAL (helper, call_conv, guint32, MONO_HANDLE_GETVAL (helper, call_conv) & 0x20);
934 if (MONO_HANDLE_GETVAL (helper, call_conv) == 0) { /* Unmanaged */
935 idx = MONO_HANDLE_GETVAL (helper, unmanaged_call_conv) - 1;
936 } else {
937 /* Managed */
938 idx = MONO_HANDLE_GETVAL (helper, call_conv) & 0x60; /* has_this + explicit_this */
939 if (MONO_HANDLE_GETVAL (helper, call_conv) & 0x02) /* varargs */
940 idx += 0x05;
943 sigbuffer_add_byte (&buf, idx);
944 sigbuffer_add_value (&buf, nargs);
945 encode_reflection_type (assembly, MONO_HANDLE_NEW_GET (MonoReflectionType, helper, return_type), &buf, error);
946 goto_if_nok (error, fail);
947 MonoArrayHandle modreqs;
948 modreqs = MONO_HANDLE_NEW_GET (MonoArray, helper, modreqs);
949 MonoArrayHandle modopts;
950 modopts = MONO_HANDLE_NEW_GET (MonoArray, helper, modopts);
951 for (i = 0; i < nargs; ++i) {
952 if (!encode_sighelper_arg (assembly, i, arguments, modreqs, modopts, &buf, error))
953 goto fail;
955 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
956 sigbuffer_free (&buf);
958 return idx;
959 fail:
960 sigbuffer_free (&buf);
961 return 0;
963 #else /* DISABLE_REFLECTION_EMIT */
964 guint32
965 mono_dynimage_encode_reflection_sighelper (MonoDynamicImage *assembly, MonoReflectionSigHelperHandle helper, MonoError *error)
967 g_assert_not_reached ();
968 return 0;
970 #endif /* DISABLE_REFLECTION_EMIT */
972 static gboolean
973 encode_reflection_types (MonoDynamicImage *assembly, MonoArrayHandle sig_arguments, int i, SigBuffer *buf, MonoError *error)
975 HANDLE_FUNCTION_ENTER ();
976 error_init (error);
977 MonoReflectionTypeHandle type = MONO_HANDLE_NEW (MonoReflectionType, NULL);
978 MONO_HANDLE_ARRAY_GETREF (type, sig_arguments, i);
979 encode_reflection_type (assembly, type, buf, error);
980 HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
983 static MonoArrayHandle
984 reflection_sighelper_get_signature_local (MonoReflectionSigHelperHandle sig, MonoError *error)
986 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, sig, module);
987 MonoDynamicImage *assembly = MONO_HANDLE_IS_NULL (module) ? NULL : MONO_HANDLE_GETVAL (module, dynamic_image);
988 MonoArrayHandle sig_arguments = MONO_HANDLE_NEW_GET (MonoArray, sig, arguments);
989 guint32 na = MONO_HANDLE_IS_NULL (sig_arguments) ? 0 : mono_array_handle_length (sig_arguments);
990 guint32 buflen, i;
991 SigBuffer buf;
993 error_init (error);
995 sigbuffer_init (&buf, 32);
997 sigbuffer_add_value (&buf, 0x07);
998 sigbuffer_add_value (&buf, na);
999 if (assembly != NULL){
1000 for (i = 0; i < na; ++i) {
1001 if (!encode_reflection_types (assembly, sig_arguments, i, &buf, error))
1002 goto fail;
1006 buflen = buf.p - buf.buf;
1007 MonoArrayHandle result;
1008 result = mono_array_new_handle (mono_domain_get (), mono_defaults.byte_class, buflen, error);
1009 goto_if_nok (error, fail);
1010 uint32_t gchandle;
1011 void *base;
1012 base = MONO_ARRAY_HANDLE_PIN (result, char, 0, &gchandle);
1013 memcpy (base, buf.buf, buflen);
1014 sigbuffer_free (&buf);
1015 mono_gchandle_free_internal (gchandle);
1016 return result;
1017 fail:
1018 sigbuffer_free (&buf);
1019 return MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
1022 static MonoArrayHandle
1023 reflection_sighelper_get_signature_field (MonoReflectionSigHelperHandle sig, MonoError *error)
1025 MonoReflectionModuleBuilderHandle module = MONO_HANDLE_NEW_GET (MonoReflectionModuleBuilder, sig, module);
1026 MonoDynamicImage *assembly = MONO_HANDLE_GETVAL (module, dynamic_image);
1027 MonoArrayHandle sig_arguments = MONO_HANDLE_NEW_GET (MonoArray, sig, arguments);
1028 guint32 na = MONO_HANDLE_IS_NULL (sig_arguments) ? 0 : mono_array_handle_length (sig_arguments);
1029 guint32 buflen, i;
1030 SigBuffer buf;
1032 error_init (error);
1034 sigbuffer_init (&buf, 32);
1036 sigbuffer_add_value (&buf, 0x06);
1037 for (i = 0; i < na; ++i) {
1038 if (! encode_reflection_types (assembly, sig_arguments, i, &buf, error))
1039 goto fail;
1042 buflen = buf.p - buf.buf;
1043 MonoArrayHandle result;
1044 result = mono_array_new_handle (mono_domain_get (), mono_defaults.byte_class, buflen, error);
1045 goto_if_nok (error, fail);
1046 uint32_t gchandle;
1047 void *base;
1048 base = MONO_ARRAY_HANDLE_PIN (result, char, 0, &gchandle);
1049 memcpy (base, buf.buf, buflen);
1050 sigbuffer_free (&buf);
1051 mono_gchandle_free_internal (gchandle);
1053 return result;
1054 fail:
1055 sigbuffer_free (&buf);
1056 return MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
1059 static char*
1060 type_get_fully_qualified_name (MonoType *type)
1062 MONO_REQ_GC_NEUTRAL_MODE;
1064 return mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_ASSEMBLY_QUALIFIED);
1067 #ifndef DISABLE_REFLECTION_EMIT_SAVE
1068 guint32
1069 mono_dynimage_save_encode_marshal_blob (MonoDynamicImage *assembly, MonoReflectionMarshal *minfo, MonoError *error)
1071 MONO_REQ_GC_UNSAFE_MODE;
1073 error_init (error);
1075 char *str;
1076 SigBuffer buf;
1077 guint32 idx, len;
1079 sigbuffer_init (&buf, 32);
1081 sigbuffer_add_value (&buf, minfo->type);
1083 switch (minfo->type) {
1084 case MONO_NATIVE_BYVALTSTR:
1085 case MONO_NATIVE_BYVALARRAY:
1086 sigbuffer_add_value (&buf, minfo->count);
1087 break;
1088 case MONO_NATIVE_LPARRAY:
1089 if (minfo->eltype || minfo->has_size) {
1090 sigbuffer_add_value (&buf, minfo->eltype);
1091 if (minfo->has_size) {
1092 sigbuffer_add_value (&buf, minfo->param_num != -1? minfo->param_num: 0);
1093 sigbuffer_add_value (&buf, minfo->count != -1? minfo->count: 0);
1095 /* LAMESPEC: ElemMult is undocumented */
1096 sigbuffer_add_value (&buf, minfo->param_num != -1? 1: 0);
1099 break;
1100 case MONO_NATIVE_SAFEARRAY:
1101 if (minfo->eltype)
1102 sigbuffer_add_value (&buf, minfo->eltype);
1103 break;
1104 case MONO_NATIVE_CUSTOM:
1105 if (minfo->guid) {
1106 str = mono_string_to_utf8_checked_internal (minfo->guid, error);
1107 if (!is_ok (error)) {
1108 sigbuffer_free (&buf);
1109 return 0;
1111 len = strlen (str);
1112 sigbuffer_add_value (&buf, len);
1113 sigbuffer_add_mem (&buf, str, len);
1114 g_free (str);
1115 } else {
1116 sigbuffer_add_value (&buf, 0);
1118 /* native type name */
1119 sigbuffer_add_value (&buf, 0);
1120 /* custom marshaler type name */
1121 if (minfo->marshaltype || minfo->marshaltyperef) {
1122 if (minfo->marshaltyperef) {
1123 MonoType *marshaltype = mono_reflection_type_get_handle ((MonoReflectionType*)minfo->marshaltyperef, error);
1124 if (!is_ok (error)) {
1125 sigbuffer_free (&buf);
1126 return 0;
1128 str = type_get_fully_qualified_name (marshaltype);
1129 } else {
1130 str = mono_string_to_utf8_checked_internal (minfo->marshaltype, error);
1131 if (!is_ok (error)) {
1132 sigbuffer_free (&buf);
1133 return 0;
1136 len = strlen (str);
1137 sigbuffer_add_value (&buf, len);
1138 sigbuffer_add_mem (&buf, str, len);
1139 g_free (str);
1140 } else {
1141 /* FIXME: Actually a bug, since this field is required. Punting for now ... */
1142 sigbuffer_add_value (&buf, 0);
1144 if (minfo->mcookie) {
1145 str = mono_string_to_utf8_checked_internal (minfo->mcookie, error);
1146 if (!is_ok (error)) {
1147 sigbuffer_free (&buf);
1148 return 0;
1150 len = strlen (str);
1151 sigbuffer_add_value (&buf, len);
1152 sigbuffer_add_mem (&buf, str, len);
1153 g_free (str);
1154 } else {
1155 sigbuffer_add_value (&buf, 0);
1157 break;
1158 default:
1159 break;
1161 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
1162 sigbuffer_free (&buf);
1163 return idx;
1166 guint32
1167 mono_dynimage_save_encode_property_signature (MonoDynamicImage *assembly, MonoReflectionPropertyBuilder *fb, MonoError *error)
1169 MONO_REQ_GC_UNSAFE_MODE;
1171 error_init (error);
1173 SigBuffer buf;
1174 guint32 nparams = 0;
1175 MonoReflectionMethodBuilder *mb = fb->get_method;
1176 MonoReflectionMethodBuilder *smb = fb->set_method;
1177 guint32 idx, i;
1179 if (mb && mb->parameters)
1180 nparams = mono_array_length_internal (mb->parameters);
1181 if (!mb && smb && smb->parameters)
1182 nparams = mono_array_length_internal (smb->parameters) - 1;
1183 sigbuffer_init (&buf, 32);
1184 if (fb->call_conv & 0x20)
1185 sigbuffer_add_byte (&buf, 0x28);
1186 else
1187 sigbuffer_add_byte (&buf, 0x08);
1188 sigbuffer_add_value (&buf, nparams);
1189 if (mb) {
1190 encode_reflection_type_raw (assembly, (MonoReflectionType*)mb->rtype, &buf, error);
1191 if (!is_ok (error))
1192 goto fail;
1193 for (i = 0; i < nparams; ++i) {
1194 MonoReflectionType *pt = mono_array_get_internal (mb->parameters, MonoReflectionType*, i);
1195 encode_reflection_type_raw (assembly, pt, &buf, error);
1196 if (!is_ok (error))
1197 goto fail;
1199 } else if (smb && smb->parameters) {
1200 /* the property type is the last param */
1201 encode_reflection_type_raw (assembly, mono_array_get_internal (smb->parameters, MonoReflectionType*, nparams), &buf, error);
1202 if (!is_ok (error))
1203 goto fail;
1205 for (i = 0; i < nparams; ++i) {
1206 MonoReflectionType *pt = mono_array_get_internal (smb->parameters, MonoReflectionType*, i);
1207 encode_reflection_type_raw (assembly, pt, &buf, error);
1208 if (!is_ok (error))
1209 goto fail;
1211 } else {
1212 encode_reflection_type_raw (assembly, (MonoReflectionType*)fb->type, &buf, error);
1213 if (!is_ok (error))
1214 goto fail;
1217 idx = sigbuffer_add_to_blob_cached (assembly, &buf);
1218 sigbuffer_free (&buf);
1219 return idx;
1220 fail:
1221 sigbuffer_free (&buf);
1222 return 0;
1226 #else /*DISABLE_REFLECTION_EMIT_SAVE*/
1227 guint32
1228 mono_dynimage_save_encode_marshal_blob (MonoDynamicImage *assembly, MonoReflectionMarshal *minfo, MonoError *error)
1230 g_assert_not_reached ();
1231 return 0;
1234 guint32
1235 mono_dynimage_save_encode_property_signature (MonoDynamicImage *assembly, MonoReflectionPropertyBuilder *fb, MonoError *error)
1237 g_assert_not_reached ();
1238 return 0;
1240 #endif /*DISABLE_REFLECTION_EMIT_SAVE*/
1242 #ifndef DISABLE_REFLECTION_EMIT
1243 MonoArrayHandle
1244 ves_icall_SignatureHelper_get_signature_local (MonoReflectionSigHelperHandle sig, MonoError *error)
1246 error_init (error);
1247 return reflection_sighelper_get_signature_local (sig, error);
1250 MonoArrayHandle
1251 ves_icall_SignatureHelper_get_signature_field (MonoReflectionSigHelperHandle sig, MonoError *error)
1253 error_init (error);
1254 return reflection_sighelper_get_signature_field (sig, error);
1256 #else /* DISABLE_REFLECTION_EMIT */
1257 MonoArrayHandle
1258 ves_icall_SignatureHelper_get_signature_local (MonoReflectionSigHelperHandle sig, MonoError *error)
1260 error_init (error);
1261 g_assert_not_reached ();
1262 return MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
1265 MonoArrayHandle
1266 ves_icall_SignatureHelper_get_signature_field (MonoReflectionSigHelperHandle sig, MonoError *error)
1268 error_init (error);
1269 g_assert_not_reached ();
1270 return MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
1273 #endif /* DISABLE_REFLECTION_EMIT */