2 * method-builder.c: Functions for creating IL methods at runtime.
5 * Paolo Molaro (lupus@ximian.com)
7 * (C) 2002 Ximian, Inc. http://www.ximian.com
13 #include "mono/metadata/method-builder.h"
14 #include "mono/metadata/tabledefs.h"
15 #include "mono/metadata/exception.h"
16 #include "mono/metadata/appdomain.h"
17 #include "mono/metadata/debug-helpers.h"
18 #include "mono/metadata/metadata-internals.h"
19 #include "mono/metadata/domain-internals.h"
23 /* #define DEBUG_RUNTIME_CODE */
25 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
29 #include "mono/cil/opcode.def"
34 #ifdef DEBUG_RUNTIME_CODE
36 indenter (MonoDisHelper *dh, MonoMethod *method, guint32 ip_offset)
38 return g_strdup (" ");
41 static MonoDisHelper marshal_dh = {
51 static MonoMethodBuilder *
52 mono_mb_new_base (MonoClass *klass, MonoWrapperType type)
54 MonoMethodBuilder *mb;
57 g_assert (klass != NULL);
59 mb = g_new0 (MonoMethodBuilder, 1);
61 mb->method = m = (MonoMethod *)g_new0 (MonoMethodWrapper, 1);
65 m->wrapper_type = type;
68 mb->code = g_malloc (mb->code_size);
74 mono_mb_new_no_dup_name (MonoClass *klass, const char *name, MonoWrapperType type)
76 MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
77 mb->name = (char*)name;
78 mb->no_dup_name = TRUE;
83 mono_mb_new (MonoClass *klass, const char *name, MonoWrapperType type)
85 MonoMethodBuilder *mb = mono_mb_new_base (klass, type);
86 mb->name = g_strdup (name);
91 mono_mb_free (MonoMethodBuilder *mb)
93 g_list_free (mb->locals_list);
104 mono_mb_add_local (MonoMethodBuilder *mb, MonoType *type)
108 g_assert (mb != NULL);
109 g_assert (type != NULL);
112 mb->locals_list = g_list_append (mb->locals_list, type);
119 * mono_mb_create_method:
121 * Create a MonoMethod from this method builder.
122 * Returns: the newly created method.
124 * LOCKING: Takes the loader lock.
127 mono_mb_create_method (MonoMethodBuilder *mb, MonoMethodSignature *signature, int max_stack)
129 MonoMethodHeader *header;
130 MonoMethodWrapper *mw;
136 g_assert (mb != NULL);
138 mp = mb->method->klass->image->mempool;
144 method->name = mb->name;
145 method->dynamic = TRUE;
147 ((MonoMethodNormal *)method)->header = header = (MonoMethodHeader *)
148 g_malloc0 (sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
150 header->code = mb->code;
152 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
153 header->locals [i] = mono_metadata_type_dup (NULL, (MonoType*)l->data);
156 /* Realloc the method info into a mempool */
158 method = mono_mempool_alloc0 (mp, sizeof (MonoMethodWrapper));
159 memcpy (method, mb->method, sizeof (MonoMethodWrapper));
162 method->name = mb->name;
164 method->name = mono_mempool_strdup (mp, mb->name);
166 ((MonoMethodNormal *)method)->header = header = (MonoMethodHeader *)
167 mono_mempool_alloc0 (mp, sizeof (MonoMethodHeader) + mb->locals * sizeof (MonoType *));
169 header->code = mono_mempool_alloc (mp, mb->pos);
170 memcpy ((char*)header->code, mb->code, mb->pos);
172 for (i = 0, l = mb->locals_list; l; l = l->next, i++) {
173 header->locals [i] = (MonoType *)l->data;
180 header->max_stack = max_stack;
182 method->signature = signature;
184 header->code_size = mb->pos;
185 header->num_locals = mb->locals;
186 header->init_locals = TRUE;
188 mw = (MonoMethodWrapper*) mb->method;
189 i = g_list_length (mw->method_data);
193 l = g_list_reverse (mw->method_data);
195 data = g_malloc (sizeof (gpointer) * (i + 1));
197 data = mono_mempool_alloc (mp, sizeof (gpointer) * (i + 1));
198 /* store the size in the first element */
199 data [0] = GUINT_TO_POINTER (i);
201 for (tmp = l; tmp; tmp = tmp->next) {
202 data [i++] = tmp->data;
206 ((MonoMethodWrapper*)method)->method_data = data;
209 static int total_code = 0;
210 static int total_alloc = 0;
211 total_code += mb->pos;
212 total_alloc += mb->code_size;
213 g_print ("code size: %d of %d (allocated: %d)\n", mb->pos, total_code, total_alloc);
216 #ifdef DEBUG_RUNTIME_CODE
217 printf ("RUNTIME CODE FOR %s\n", mono_method_full_name (method, TRUE));
218 printf ("%s\n", mono_disasm_code (&marshal_dh, method, mb->code, mb->code + mb->pos));
221 mono_loader_unlock ();
226 mono_mb_add_data (MonoMethodBuilder *mb, gpointer data)
228 MonoMethodWrapper *mw;
230 g_assert (mb != NULL);
232 mw = (MonoMethodWrapper *)mb->method;
234 /* one O(n) is enough */
235 mw->method_data = g_list_prepend (mw->method_data, data);
237 return g_list_length (mw->method_data);
241 mono_mb_patch_addr (MonoMethodBuilder *mb, int pos, int value)
243 mb->code [pos] = value & 0xff;
244 mb->code [pos + 1] = (value >> 8) & 0xff;
245 mb->code [pos + 2] = (value >> 16) & 0xff;
246 mb->code [pos + 3] = (value >> 24) & 0xff;
250 mono_mb_patch_addr_s (MonoMethodBuilder *mb, int pos, gint8 value)
252 *((gint8 *)(&mb->code [pos])) = value;
256 mono_mb_emit_byte (MonoMethodBuilder *mb, guint8 op)
258 if (mb->pos >= mb->code_size) {
259 mb->code_size += mb->code_size >> 1;
260 mb->code = g_realloc (mb->code, mb->code_size);
263 mb->code [mb->pos++] = op;
267 mono_mb_emit_ldflda (MonoMethodBuilder *mb, gint32 offset)
269 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
270 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
273 mono_mb_emit_icon (mb, offset);
274 mono_mb_emit_byte (mb, CEE_ADD);
279 mono_mb_emit_i4 (MonoMethodBuilder *mb, gint32 data)
281 if ((mb->pos + 4) >= mb->code_size) {
282 mb->code_size += mb->code_size >> 1;
283 mb->code = g_realloc (mb->code, mb->code_size);
286 mono_mb_patch_addr (mb, mb->pos, data);
291 mono_mb_emit_i2 (MonoMethodBuilder *mb, gint16 data)
293 if ((mb->pos + 2) >= mb->code_size) {
294 mb->code_size += mb->code_size >> 1;
295 mb->code = g_realloc (mb->code, mb->code_size);
298 mb->code [mb->pos] = data & 0xff;
299 mb->code [mb->pos + 1] = (data >> 8) & 0xff;
304 mono_mb_emit_op (MonoMethodBuilder *mb, guint8 op, gpointer data)
306 mono_mb_emit_byte (mb, op);
307 mono_mb_emit_i4 (mb, mono_mb_add_data (mb, data));
311 mono_mb_emit_ldstr (MonoMethodBuilder *mb, char *str)
313 mono_mb_emit_op (mb, CEE_LDSTR, str);
317 mono_mb_emit_ldarg (MonoMethodBuilder *mb, guint argnum)
320 mono_mb_emit_byte (mb, CEE_LDARG_0 + argnum);
321 } else if (argnum < 256) {
322 mono_mb_emit_byte (mb, CEE_LDARG_S);
323 mono_mb_emit_byte (mb, argnum);
325 mono_mb_emit_byte (mb, CEE_PREFIX1);
326 mono_mb_emit_byte (mb, CEE_LDARG);
327 mono_mb_emit_i2 (mb, argnum);
332 mono_mb_emit_ldarg_addr (MonoMethodBuilder *mb, guint argnum)
335 mono_mb_emit_byte (mb, CEE_LDARGA_S);
336 mono_mb_emit_byte (mb, argnum);
338 mono_mb_emit_byte (mb, CEE_PREFIX1);
339 mono_mb_emit_byte (mb, CEE_LDARGA);
340 mono_mb_emit_i2 (mb, argnum);
345 mono_mb_emit_ldloc_addr (MonoMethodBuilder *mb, guint locnum)
348 mono_mb_emit_byte (mb, CEE_LDLOCA_S);
349 mono_mb_emit_byte (mb, locnum);
351 mono_mb_emit_byte (mb, CEE_PREFIX1);
352 mono_mb_emit_byte (mb, CEE_LDLOCA);
353 mono_mb_emit_i2 (mb, locnum);
358 mono_mb_emit_ldloc (MonoMethodBuilder *mb, guint num)
361 mono_mb_emit_byte (mb, CEE_LDLOC_0 + num);
362 } else if (num < 256) {
363 mono_mb_emit_byte (mb, CEE_LDLOC_S);
364 mono_mb_emit_byte (mb, num);
366 mono_mb_emit_byte (mb, CEE_PREFIX1);
367 mono_mb_emit_byte (mb, CEE_LDLOC);
368 mono_mb_emit_i2 (mb, num);
373 mono_mb_emit_stloc (MonoMethodBuilder *mb, guint num)
376 mono_mb_emit_byte (mb, CEE_STLOC_0 + num);
377 } else if (num < 256) {
378 mono_mb_emit_byte (mb, CEE_STLOC_S);
379 mono_mb_emit_byte (mb, num);
381 mono_mb_emit_byte (mb, CEE_PREFIX1);
382 mono_mb_emit_byte (mb, CEE_STLOC);
383 mono_mb_emit_i2 (mb, num);
388 mono_mb_emit_icon (MonoMethodBuilder *mb, gint32 value)
390 if (value >= -1 && value < 8) {
391 mono_mb_emit_byte (mb, CEE_LDC_I4_0 + value);
392 } else if (value >= -128 && value <= 127) {
393 mono_mb_emit_byte (mb, CEE_LDC_I4_S);
394 mono_mb_emit_byte (mb, value);
396 mono_mb_emit_byte (mb, CEE_LDC_I4);
397 mono_mb_emit_i4 (mb, value);
402 mono_mb_get_label (MonoMethodBuilder *mb)
408 mono_mb_get_pos (MonoMethodBuilder *mb)
414 mono_mb_emit_branch (MonoMethodBuilder *mb, guint8 op)
417 mono_mb_emit_byte (mb, op);
419 mono_mb_emit_i4 (mb, 0);
424 mono_mb_emit_short_branch (MonoMethodBuilder *mb, guint8 op)
427 mono_mb_emit_byte (mb, op);
429 mono_mb_emit_byte (mb, 0);
435 mono_mb_emit_branch_label (MonoMethodBuilder *mb, guint8 op, guint32 label)
437 mono_mb_emit_byte (mb, op);
438 mono_mb_emit_i4 (mb, label - (mb->pos + 4));
442 mono_mb_patch_branch (MonoMethodBuilder *mb, guint32 pos)
444 mono_mb_patch_addr (mb, pos, mb->pos - (pos + 4));
448 mono_mb_patch_short_branch (MonoMethodBuilder *mb, guint32 pos)
450 mono_mb_patch_addr_s (mb, pos, mb->pos - (pos + 1));
454 mono_mb_emit_ptr (MonoMethodBuilder *mb, gpointer ptr)
456 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
457 mono_mb_emit_op (mb, CEE_MONO_LDPTR, ptr);
461 mono_mb_emit_calli (MonoMethodBuilder *mb, MonoMethodSignature *sig)
463 mono_mb_emit_op (mb, CEE_CALLI, sig);
467 mono_mb_emit_managed_call (MonoMethodBuilder *mb, MonoMethod *method, MonoMethodSignature *opt_sig)
469 mono_mb_emit_op (mb, CEE_CALL, method);
473 mono_mb_emit_native_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, gpointer func)
475 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
476 mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
477 mono_mb_emit_ptr (mb, func);
478 mono_mb_emit_calli (mb, sig);
479 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
480 mono_mb_emit_byte (mb, CEE_MONO_RESTORE_LMF);
484 mono_mb_emit_icall (MonoMethodBuilder *mb, gpointer func)
486 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
487 mono_mb_emit_op (mb, CEE_MONO_ICALL, func);
491 mono_mb_emit_exception_full (MonoMethodBuilder *mb, const char *exc_nspace, const char *exc_name, const char *msg)
493 MonoMethod *ctor = NULL;
495 MonoClass *mme = mono_class_from_name (mono_defaults.corlib, exc_nspace, exc_name);
496 mono_class_init (mme);
497 ctor = mono_class_get_method_from_name (mme, ".ctor", 0);
499 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
501 mono_mb_emit_byte (mb, CEE_DUP);
502 mono_mb_emit_ldflda (mb, G_STRUCT_OFFSET (MonoException, message));
503 mono_mb_emit_ldstr (mb, (char*)msg);
504 mono_mb_emit_byte (mb, CEE_STIND_REF);
506 mono_mb_emit_byte (mb, CEE_THROW);
510 mono_mb_emit_exception (MonoMethodBuilder *mb, const char *exc_name, const char *msg)
512 mono_mb_emit_exception_full (mb, "System", exc_name, msg);
516 mono_mb_emit_add_to_local (MonoMethodBuilder *mb, guint16 local, gint32 incr)
518 mono_mb_emit_ldloc (mb, local);
519 mono_mb_emit_icon (mb, incr);
520 mono_mb_emit_byte (mb, CEE_ADD);
521 mono_mb_emit_stloc (mb, local);