1 /**
2 * \file
3 * PLEASE NOTE: This is a research prototype.
4 *
5 *
6 * interp.c: Interpreter for CIL byte codes
7 *
8 * Authors:
9 * Paolo Molaro (lupus@ximian.com)
10 * Miguel de Icaza (miguel@ximian.com)
11 * Dietmar Maurer (dietmar@ximian.com)
12 *
13 * (C) 2001, 2002 Ximian, Inc.
14 */
15 #ifndef __USE_ISOC99
16 #define __USE_ISOC99
17 #endif
18 #include "config.h"
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <glib.h>
24 #include <signal.h>
25 #include <math.h>
26 #include <locale.h>
27
28 #include <mono/utils/gc_wrapper.h>
29
30 #ifdef HAVE_ALLOCA_H
31 # include <alloca.h>
32 #else
33 # ifdef __CYGWIN__
34 # define alloca __builtin_alloca
35 # endif
36 #endif
37
38 /* trim excessive headers */
39 #include <mono/metadata/image.h>
40 #include <mono/metadata/assembly-internals.h>
41 #include <mono/metadata/cil-coff.h>
42 #include <mono/metadata/mono-endian.h>
43 #include <mono/metadata/tabledefs.h>
44 #include <mono/metadata/tokentype.h>
45 #include <mono/metadata/loader.h>
46 #include <mono/metadata/threads.h>
47 #include <mono/metadata/threadpool.h>
48 #include <mono/metadata/profiler-private.h>
49 #include <mono/metadata/appdomain.h>
50 #include <mono/metadata/reflection.h>
51 #include <mono/metadata/exception.h>
52 #include <mono/metadata/verify.h>
53 #include <mono/metadata/opcodes.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/mono-config.h>
56 #include <mono/metadata/marshal.h>
57 #include <mono/metadata/environment.h>
58 #include <mono/metadata/mono-debug.h>
59 #include <mono/utils/atomic.h>
60
61 #include "interp.h"
62 #include "interp-internals.h"
63 #include "mintops.h"
64 #include "hacks.h"
65
66 #include <mono/mini/mini.h>
67 #include <mono/mini/mini-runtime.h>
68 #include <mono/mini/aot-runtime.h>
69 #include <mono/mini/jit-icalls.h>
70 #include <mono/mini/debugger-agent.h>
71
72 #ifdef TARGET_ARM
73 #include <mono/mini/mini-arm.h>
74 #endif
75
76 /* Mingw 2.1 doesnt need this any more, but leave it in for now for older versions */
77 #ifdef _WIN32
78 #define isnan _isnan
79 #define finite _finite
80 #endif
81 #ifndef HAVE_FINITE
82 #ifdef HAVE_ISFINITE
83 #define finite isfinite
84 #endif
85 #endif
86
87 static inline void
init_frame(InterpFrame * frame,InterpFrame * parent_frame,InterpMethod * rmethod,stackval * method_args,stackval * method_retval)88 init_frame (InterpFrame *frame, InterpFrame *parent_frame, InterpMethod *rmethod, stackval *method_args, stackval *method_retval)
89 {
90 frame->parent = parent_frame;
91 frame->stack_args = method_args;
92 frame->retval = method_retval;
93 frame->imethod = rmethod;
94 frame->ex = NULL;
95 frame->ip = NULL;
96 frame->invoke_trap = 0;
97 }
98
99 #define INIT_FRAME(frame,parent_frame,method_args,method_retval,domain,mono_method,error) do { \
100 InterpMethod *_rmethod = mono_interp_get_imethod ((domain), (mono_method), (error)); \
101 init_frame ((frame), (parent_frame), _rmethod, (method_args), (method_retval)); \
102 } while (0)
103
104 /*
105 * List of classes whose methods will be executed by transitioning to JITted code.
106 * Used for testing.
107 */
108 GSList *jit_classes;
109 /* If TRUE, interpreted code will be interrupted at function entry/backward branches */
110 static gboolean ss_enabled;
111
112 static char* dump_frame (InterpFrame *inv);
113 static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top);
114 static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame);
115 static void interp_exec_method (InterpFrame *frame, ThreadContext *context);
116
117 typedef void (*ICallMethod) (InterpFrame *frame);
118
119 static MonoNativeTlsKey thread_context_id;
120
121 static char* dump_args (InterpFrame *inv);
122
123 #define DEBUG_INTERP 0
124 #define COUNT_OPS 0
125 #if DEBUG_INTERP
126 int mono_interp_traceopt = 2;
127 /* If true, then we output the opcodes as we interpret them */
128 static int global_tracing = 2;
129
130 static int debug_indent_level = 0;
131
132 static int break_on_method = 0;
133 static int nested_trace = 0;
134 static GList *db_methods = NULL;
135
136 static void
output_indent(void)137 output_indent (void)
138 {
139 int h;
140
141 for (h = 0; h < debug_indent_level; h++)
142 g_print (" ");
143 }
144
145 static void
db_match_method(gpointer data,gpointer user_data)146 db_match_method (gpointer data, gpointer user_data)
147 {
148 MonoMethod *m = (MonoMethod*)user_data;
149 MonoMethodDesc *desc = data;
150
151 if (mono_method_desc_full_match (desc, m))
152 break_on_method = 1;
153 }
154
155 static void
debug_enter(InterpFrame * frame,int * tracing)156 debug_enter (InterpFrame *frame, int *tracing)
157 {
158 if (db_methods) {
159 g_list_foreach (db_methods, db_match_method, (gpointer)frame->imethod->method);
160 if (break_on_method)
161 *tracing = nested_trace ? (global_tracing = 2, 3) : 2;
162 break_on_method = 0;
163 }
164 if (*tracing) {
165 MonoMethod *method = frame->imethod->method;
166 char *mn, *args = dump_args (frame);
167 debug_indent_level++;
168 output_indent ();
169 mn = mono_method_full_name (method, FALSE);
170 g_print ("(%p) Entering %s (", mono_thread_internal_current (), mn);
171 g_free (mn);
172 g_print ("%s)\n", args);
173 g_free (args);
174 }
175 }
176
177
178 #define DEBUG_LEAVE() \
179 if (tracing) { \
180 char *mn, *args; \
181 args = dump_retval (frame); \
182 output_indent (); \
183 mn = mono_method_full_name (frame->imethod->method, FALSE); \
184 g_print ("(%p) Leaving %s", mono_thread_internal_current (), mn); \
185 g_free (mn); \
186 g_print (" => %s\n", args); \
187 g_free (args); \
188 debug_indent_level--; \
189 if (tracing == 3) global_tracing = 0; \
190 }
191
192 #else
193
194 int mono_interp_traceopt = 0;
debug_enter(InterpFrame * frame,int * tracing)195 static void debug_enter (InterpFrame *frame, int *tracing)
196 {
197 }
198 #define DEBUG_LEAVE()
199
200 #endif
201
202 static void
set_resume_state(ThreadContext * context,InterpFrame * frame)203 set_resume_state (ThreadContext *context, InterpFrame *frame)
204 {
205 frame->ex = NULL;
206 context->has_resume_state = 0;
207 context->handler_frame = NULL;
208 }
209
210 /* Set the current execution state to the resume state in context */
211 #define SET_RESUME_STATE(context) do { \
212 ip = (context)->handler_ip; \
213 /* spec says stack should be empty at endfinally so it should be at the start too */ \
214 sp = frame->stack; \
215 vt_sp = (unsigned char *) sp + rtm->stack_size; \
216 if (frame->ex) { \
217 sp->data.p = frame->ex; \
218 ++sp; \
219 } \
220 set_resume_state ((context), (frame)); \
221 goto main_loop; \
222 } while (0)
223
224 static void
set_context(ThreadContext * context)225 set_context (ThreadContext *context)
226 {
227 MonoJitTlsData *jit_tls;
228
229 mono_native_tls_set_value (thread_context_id, context);
230 jit_tls = mono_tls_get_jit_tls ();
231 if (jit_tls)
232 jit_tls->interp_context = context;
233 }
234
235 static void
ves_real_abort(int line,MonoMethod * mh,const unsigned short * ip,stackval * stack,stackval * sp)236 ves_real_abort (int line, MonoMethod *mh,
237 const unsigned short *ip, stackval *stack, stackval *sp)
238 {
239 MonoError error;
240 MonoMethodHeader *header = mono_method_get_header_checked (mh, &error);
241 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
242 g_printerr ("Execution aborted in method: %s::%s\n", mh->klass->name, mh->name);
243 g_printerr ("Line=%d IP=0x%04lx, Aborted execution\n", line, ip-(const unsigned short *) header->code);
244 g_print ("0x%04x %02x\n", ip-(const unsigned short *) header->code, *ip);
245 mono_metadata_free_mh (header);
246 if (sp > stack)
247 printf ("\t[%ld] 0x%08x %0.5f\n", sp-stack, sp[-1].data.i, sp[-1].data.f);
248 }
249
250 #define ves_abort() \
251 do {\
252 ves_real_abort(__LINE__, frame->imethod->method, ip, frame->stack, sp); \
253 THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
254 } while (0);
255
256 static InterpMethod*
lookup_imethod(MonoDomain * domain,MonoMethod * method)257 lookup_imethod (MonoDomain *domain, MonoMethod *method)
258 {
259 InterpMethod *rtm;
260 MonoJitDomainInfo *info;
261
262 info = domain_jit_info (domain);
263 mono_domain_jit_code_hash_lock (domain);
264 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
265 mono_domain_jit_code_hash_unlock (domain);
266 return rtm;
267 }
268
269 #ifndef DISABLE_REMOTING
270 static gpointer
interp_get_remoting_invoke(gpointer imethod,MonoError * error)271 interp_get_remoting_invoke (gpointer imethod, MonoError *error)
272 {
273 InterpMethod *imethod_cast = (InterpMethod*) imethod;
274
275 g_assert (mono_use_interpreter);
276
277 return mono_interp_get_imethod (mono_domain_get (), mono_marshal_get_remoting_invoke (imethod_cast->method), error);
278 }
279 #endif
280
281 InterpMethod*
mono_interp_get_imethod(MonoDomain * domain,MonoMethod * method,MonoError * error)282 mono_interp_get_imethod (MonoDomain *domain, MonoMethod *method, MonoError *error)
283 {
284 InterpMethod *rtm;
285 MonoJitDomainInfo *info;
286 MonoMethodSignature *sig;
287 int i;
288
289 error_init (error);
290
291 info = domain_jit_info (domain);
292 mono_domain_jit_code_hash_lock (domain);
293 rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
294 mono_domain_jit_code_hash_unlock (domain);
295 if (rtm)
296 return rtm;
297
298 sig = mono_method_signature (method);
299
300 rtm = mono_domain_alloc0 (domain, sizeof (InterpMethod));
301 rtm->method = method;
302 rtm->domain = domain;
303 rtm->param_count = sig->param_count;
304 rtm->hasthis = sig->hasthis;
305 rtm->rtype = mini_get_underlying_type (sig->ret);
306 rtm->param_types = mono_domain_alloc0 (domain, sizeof (MonoType*) * sig->param_count);
307 for (i = 0; i < sig->param_count; ++i)
308 rtm->param_types [i] = mini_get_underlying_type (sig->params [i]);
309
310 mono_domain_jit_code_hash_lock (domain);
311 if (!mono_internal_hash_table_lookup (&info->interp_code_hash, method))
312 mono_internal_hash_table_insert (&info->interp_code_hash, method, rtm);
313 mono_domain_jit_code_hash_unlock (domain);
314
315 rtm->prof_flags = mono_profiler_get_call_instrumentation_flags (rtm->method);
316
317 return rtm;
318 }
319
320 static gpointer
interp_create_trampoline(MonoDomain * domain,MonoMethod * method,MonoError * error)321 interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError *error)
322 {
323 if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
324 method = mono_marshal_get_synchronized_wrapper (method);
325 return mono_interp_get_imethod (domain, method, error);
326 }
327
328 /*
329 * interp_push_lmf:
330 *
331 * Push an LMF frame on the LMF stack
332 * to mark the transition to native code.
333 * This is needed for the native code to
334 * be able to do stack walks.
335 */
336 static void
interp_push_lmf(MonoLMFExt * ext,InterpFrame * frame)337 interp_push_lmf (MonoLMFExt *ext, InterpFrame *frame)
338 {
339 memset (ext, 0, sizeof (MonoLMFExt));
340 ext->interp_exit = TRUE;
341 ext->interp_exit_data = frame;
342
343 mono_push_lmf (ext);
344 }
345
346 static void
interp_pop_lmf(MonoLMFExt * ext)347 interp_pop_lmf (MonoLMFExt *ext)
348 {
349 mono_pop_lmf (&ext->lmf);
350 }
351
352 static inline InterpMethod*
get_virtual_method(InterpMethod * imethod,MonoObject * obj)353 get_virtual_method (InterpMethod *imethod, MonoObject *obj)
354 {
355 MonoMethod *m = imethod->method;
356 MonoDomain *domain = imethod->domain;
357 InterpMethod *ret = NULL;
358 MonoError error;
359
360 #ifndef DISABLE_REMOTING
361 if (mono_object_is_transparent_proxy (obj)) {
362 ret = mono_interp_get_imethod (domain, mono_marshal_get_remoting_invoke_with_check (m), &error);
363 mono_error_assert_ok (&error);
364 return ret;
365 }
366 #endif
367
368 if ((m->flags & METHOD_ATTRIBUTE_FINAL) || !(m->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
369 if (m->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
370 ret = mono_interp_get_imethod (domain, mono_marshal_get_synchronized_wrapper (m), &error);
371 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
372 } else {
373 ret = imethod;
374 }
375 return ret;
376 }
377
378 mono_class_setup_vtable (obj->vtable->klass);
379
380 int slot = mono_method_get_vtable_slot (m);
381 if (mono_class_is_interface (m->klass)) {
382 g_assert (obj->vtable->klass != m->klass);
383 /* TODO: interface offset lookup is slow, go through IMT instead */
384 gboolean non_exact_match;
385 slot += mono_class_interface_offset_with_variance (obj->vtable->klass, m->klass, &non_exact_match);
386 }
387
388 MonoMethod *virtual_method = obj->vtable->klass->vtable [slot];
389 if (m->is_inflated && mono_method_get_context (m)->method_inst) {
390 MonoGenericContext context = { NULL, NULL };
391
392 if (mono_class_is_ginst (virtual_method->klass))
393 context.class_inst = mono_class_get_generic_class (virtual_method->klass)->context.class_inst;
394 else if (mono_class_is_gtd (virtual_method->klass))
395 context.class_inst = mono_class_get_generic_container (virtual_method->klass)->context.class_inst;
396 context.method_inst = mono_method_get_context (m)->method_inst;
397
398 virtual_method = mono_class_inflate_generic_method_checked (virtual_method, &context, &error);
399 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
400 }
401
402 if (virtual_method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) {
403 virtual_method = mono_marshal_get_synchronized_wrapper (virtual_method);
404 }
405
406 InterpMethod *virtual_imethod = mono_interp_get_imethod (domain, virtual_method, &error);
407 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
408 return virtual_imethod;
409 }
410
411 static void inline
stackval_from_data(MonoType * type_,stackval * result,char * data,gboolean pinvoke)412 stackval_from_data (MonoType *type_, stackval *result, char *data, gboolean pinvoke)
413 {
414 MonoType *type = mini_native_type_replace_type (type_);
415 if (type->byref) {
416 switch (type->type) {
417 case MONO_TYPE_OBJECT:
418 case MONO_TYPE_CLASS:
419 case MONO_TYPE_STRING:
420 case MONO_TYPE_ARRAY:
421 case MONO_TYPE_SZARRAY:
422 break;
423 default:
424 break;
425 }
426 result->data.p = *(gpointer*)data;
427 return;
428 }
429 switch (type->type) {
430 case MONO_TYPE_VOID:
431 return;
432 case MONO_TYPE_I1:
433 result->data.i = *(gint8*)data;
434 return;
435 case MONO_TYPE_U1:
436 case MONO_TYPE_BOOLEAN:
437 result->data.i = *(guint8*)data;
438 return;
439 case MONO_TYPE_I2:
440 result->data.i = *(gint16*)data;
441 return;
442 case MONO_TYPE_U2:
443 case MONO_TYPE_CHAR:
444 result->data.i = *(guint16*)data;
445 return;
446 case MONO_TYPE_I4:
447 result->data.i = *(gint32*)data;
448 return;
449 case MONO_TYPE_U:
450 case MONO_TYPE_I:
451 result->data.nati = *(mono_i*)data;
452 return;
453 case MONO_TYPE_PTR:
454 result->data.p = *(gpointer*)data;
455 return;
456 case MONO_TYPE_U4:
457 result->data.i = *(guint32*)data;
458 return;
459 case MONO_TYPE_R4: {
460 float tmp;
461 /* memmove handles unaligned case */
462 memmove (&tmp, data, sizeof (float));
463 result->data.f = tmp;
464 return;
465 }
466 case MONO_TYPE_I8:
467 case MONO_TYPE_U8:
468 memmove (&result->data.l, data, sizeof (gint64));
469 return;
470 case MONO_TYPE_R8:
471 memmove (&result->data.f, data, sizeof (double));
472 return;
473 case MONO_TYPE_STRING:
474 case MONO_TYPE_SZARRAY:
475 case MONO_TYPE_CLASS:
476 case MONO_TYPE_OBJECT:
477 case MONO_TYPE_ARRAY:
478 result->data.p = *(gpointer*)data;
479 return;
480 case MONO_TYPE_VALUETYPE:
481 if (type->data.klass->enumtype) {
482 stackval_from_data (mono_class_enum_basetype (type->data.klass), result, data, pinvoke);
483 return;
484 } else
485 mono_value_copy (result->data.vt, data, type->data.klass);
486 return;
487 case MONO_TYPE_GENERICINST: {
488 if (mono_type_generic_inst_is_valuetype (type)) {
489 mono_value_copy (result->data.vt, data, mono_class_from_mono_type (type));
490 return;
491 }
492 stackval_from_data (&type->data.generic_class->container_class->byval_arg, result, data, pinvoke);
493 return;
494 }
495 default:
496 g_warning ("got type 0x%02x", type->type);
497 g_assert_not_reached ();
498 }
499 }
500
501 static void inline
stackval_to_data(MonoType * type_,stackval * val,char * data,gboolean pinvoke)502 stackval_to_data (MonoType *type_, stackval *val, char *data, gboolean pinvoke)
503 {
504 MonoType *type = mini_native_type_replace_type (type_);
505 if (type->byref) {
506 gpointer *p = (gpointer*)data;
507 *p = val->data.p;
508 return;
509 }
510 /* printf ("TODAT0 %p\n", data); */
511 switch (type->type) {
512 case MONO_TYPE_I1:
513 case MONO_TYPE_U1: {
514 guint8 *p = (guint8*)data;
515 *p = val->data.i;
516 return;
517 }
518 case MONO_TYPE_BOOLEAN: {
519 guint8 *p = (guint8*)data;
520 *p = (val->data.i != 0);
521 return;
522 }
523 case MONO_TYPE_I2:
524 case MONO_TYPE_U2:
525 case MONO_TYPE_CHAR: {
526 guint16 *p = (guint16*)data;
527 *p = val->data.i;
528 return;
529 }
530 case MONO_TYPE_I: {
531 mono_i *p = (mono_i*)data;
532 /* In theory the value used by stloc should match the local var type
533 but in practice it sometimes doesn't (a int32 gets dup'd and stloc'd into
534 a native int - both by csc and mcs). Not sure what to do about sign extension
535 as it is outside the spec... doing the obvious */
536 *p = (mono_i)val->data.nati;
537 return;
538 }
539 case MONO_TYPE_U: {
540 mono_u *p = (mono_u*)data;
541 /* see above. */
542 *p = (mono_u)val->data.nati;
543 return;
544 }
545 case MONO_TYPE_I4:
546 case MONO_TYPE_U4: {
547 gint32 *p = (gint32*)data;
548 *p = val->data.i;
549 return;
550 }
551 case MONO_TYPE_I8:
552 case MONO_TYPE_U8: {
553 gint64 *p = (gint64*)data;
554 *p = val->data.l;
555 return;
556 }
557 case MONO_TYPE_R4: {
558 float *p = (float*)data;
559 *p = val->data.f;
560 return;
561 }
562 case MONO_TYPE_R8: {
563 double *p = (double*)data;
564 *p = val->data.f;
565 return;
566 }
567 case MONO_TYPE_STRING:
568 case MONO_TYPE_SZARRAY:
569 case MONO_TYPE_CLASS:
570 case MONO_TYPE_OBJECT:
571 case MONO_TYPE_ARRAY: {
572 gpointer *p = (gpointer *) data;
573 mono_gc_wbarrier_generic_store (p, val->data.p);
574 return;
575 }
576 case MONO_TYPE_PTR: {
577 gpointer *p = (gpointer *) data;
578 *p = val->data.p;
579 return;
580 }
581 case MONO_TYPE_VALUETYPE:
582 if (type->data.klass->enumtype) {
583 stackval_to_data (mono_class_enum_basetype (type->data.klass), val, data, pinvoke);
584 return;
585 } else
586 mono_value_copy (data, val->data.vt, type->data.klass);
587 return;
588 case MONO_TYPE_GENERICINST: {
589 MonoClass *container_class = type->data.generic_class->container_class;
590
591 if (container_class->valuetype && !container_class->enumtype) {
592 mono_value_copy (data, val->data.vt, mono_class_from_mono_type (type));
593 return;
594 }
595 stackval_to_data (&type->data.generic_class->container_class->byval_arg, val, data, pinvoke);
596 return;
597 }
598 default:
599 g_warning ("got type %x", type->type);
600 g_assert_not_reached ();
601 }
602 }
603
604 /*
605 * interp_throw:
606 * Throw an exception from the interpreter.
607 */
608 static void
interp_throw(ThreadContext * context,MonoException * ex,InterpFrame * frame,gconstpointer ip,gboolean rethrow)609 interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, gconstpointer ip, gboolean rethrow)
610 {
611 MonoLMFExt ext;
612
613 interp_push_lmf (&ext, frame);
614 frame->ip = ip;
615 frame->ex = ex;
616
617 if (!rethrow) {
618 ex->stack_trace = NULL;
619 ex->trace_ips = NULL;
620 }
621
622 MonoContext ctx;
623 memset (&ctx, 0, sizeof (MonoContext));
624 MONO_CONTEXT_SET_SP (&ctx, frame);
625
626 /*
627 * Call the JIT EH code. The EH code will call back to us using:
628 * - mono_interp_set_resume_state ()/run_finally ()/run_filter ().
629 * Since ctx.ip is 0, this will start unwinding from the LMF frame
630 * pushed above, which points to our frames.
631 */
632 mono_handle_exception (&ctx, (MonoObject*)ex);
633
634 interp_pop_lmf (&ext);
635
636 g_assert (context->has_resume_state);
637 }
638
639 static void
fill_in_trace(MonoException * exception,InterpFrame * frame)640 fill_in_trace (MonoException *exception, InterpFrame *frame)
641 {
642 MonoError error;
643 char *stack_trace = dump_frame (frame);
644 MonoDomain *domain = frame->imethod->domain;
645 (exception)->stack_trace = mono_string_new_checked (domain, stack_trace, &error);
646 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
647 (exception)->trace_ips = get_trace_ips (domain, frame);
648 g_free (stack_trace);
649 }
650
651 #define FILL_IN_TRACE(exception, frame) fill_in_trace(exception, frame)
652
653 #define THROW_EX_GENERAL(exception,ex_ip, rethrow) \
654 do { \
655 interp_throw (context, (exception), (frame), (ex_ip), (rethrow)); \
656 if (frame == context->handler_frame) \
657 SET_RESUME_STATE (context); \
658 else \
659 goto exit_frame; \
660 } while (0)
661
662 #define THROW_EX(exception,ex_ip) THROW_EX_GENERAL ((exception), (ex_ip), FALSE)
663
664 /*
665 * Its possible for child_frame.ex to contain an unthrown exception, if the transform phase
666 * produced one.
667 */
668 #define CHECK_CHILD_EX(child_frame, ip) do { \
669 if ((child_frame).ex) \
670 THROW_EX ((child_frame).ex, (ip)); \
671 } while (0)
672
673 static MonoObject*
ves_array_create(InterpFrame * frame,MonoDomain * domain,MonoClass * klass,MonoMethodSignature * sig,stackval * values)674 ves_array_create (InterpFrame *frame, MonoDomain *domain, MonoClass *klass, MonoMethodSignature *sig, stackval *values)
675 {
676 uintptr_t *lengths;
677 intptr_t *lower_bounds;
678 MonoObject *obj;
679 MonoError error;
680 int i;
681
682 lengths = alloca (sizeof (uintptr_t) * klass->rank * 2);
683 for (i = 0; i < sig->param_count; ++i) {
684 lengths [i] = values->data.i;
685 values ++;
686 }
687 if (klass->rank == sig->param_count) {
688 /* Only lengths provided. */
689 lower_bounds = NULL;
690 } else {
691 /* lower bounds are first. */
692 lower_bounds = (intptr_t *) lengths;
693 lengths += klass->rank;
694 }
695 obj = (MonoObject*) mono_array_new_full_checked (domain, klass, lengths, lower_bounds, &error);
696 if (!mono_error_ok (&error)) {
697 frame->ex = mono_error_convert_to_exception (&error);
698 FILL_IN_TRACE (frame->ex, frame);
699 }
700 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
701 return obj;
702 }
703
704 static gint32
ves_array_calculate_index(MonoArray * ao,stackval * sp,InterpFrame * frame,gboolean safe)705 ves_array_calculate_index (MonoArray *ao, stackval *sp, InterpFrame *frame, gboolean safe)
706 {
707 g_assert (!frame->ex);
708 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
709
710 guint32 pos = 0;
711 if (ao->bounds) {
712 for (gint32 i = 0; i < ac->rank; i++) {
713 guint32 idx = sp [i].data.i;
714 guint32 lower = ao->bounds [i].lower_bound;
715 guint32 len = ao->bounds [i].length;
716 if (safe && (idx < lower || (idx - lower) >= len)) {
717 frame->ex = mono_get_exception_index_out_of_range ();
718 FILL_IN_TRACE (frame->ex, frame);
719 return -1;
720 }
721 pos = (pos * len) + idx - lower;
722 }
723 } else {
724 pos = sp [0].data.i;
725 if (safe && pos >= ao->max_length) {
726 frame->ex = mono_get_exception_index_out_of_range ();
727 FILL_IN_TRACE (frame->ex, frame);
728 return -1;
729 }
730 }
731 return pos;
732 }
733
734 static void
ves_array_set(InterpFrame * frame)735 ves_array_set (InterpFrame *frame)
736 {
737 stackval *sp = frame->stack_args + 1;
738
739 MonoObject *o = frame->stack_args->data.p;
740 MonoArray *ao = (MonoArray *) o;
741 MonoClass *ac = o->vtable->klass;
742
743 g_assert (ac->rank >= 1);
744
745 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
746 if (frame->ex)
747 return;
748
749 if (sp [ac->rank].data.p && !mono_object_class (o)->element_class->valuetype) {
750 MonoError error;
751 MonoObject *isinst = mono_object_isinst_checked (sp [ac->rank].data.p, mono_object_class (o)->element_class, &error);
752 mono_error_cleanup (&error);
753 if (!isinst) {
754 frame->ex = mono_get_exception_array_type_mismatch ();
755 FILL_IN_TRACE (frame->ex, frame);
756 return;
757 }
758 }
759
760 gint32 esize = mono_array_element_size (ac);
761 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
762
763 MonoType *mt = mono_method_signature (frame->imethod->method)->params [ac->rank];
764 stackval_to_data (mt, &sp [ac->rank], ea, FALSE);
765 }
766
767 static void
ves_array_get(InterpFrame * frame,gboolean safe)768 ves_array_get (InterpFrame *frame, gboolean safe)
769 {
770 stackval *sp = frame->stack_args + 1;
771
772 MonoObject *o = frame->stack_args->data.p;
773 MonoArray *ao = (MonoArray *) o;
774 MonoClass *ac = o->vtable->klass;
775
776 g_assert (ac->rank >= 1);
777
778 gint32 pos = ves_array_calculate_index (ao, sp, frame, safe);
779 if (frame->ex)
780 return;
781
782 gint32 esize = mono_array_element_size (ac);
783 gpointer ea = mono_array_addr_with_size (ao, esize, pos);
784
785 MonoType *mt = mono_method_signature (frame->imethod->method)->ret;
786 stackval_from_data (mt, frame->retval, ea, FALSE);
787 }
788
789 static gpointer
ves_array_element_address(InterpFrame * frame,MonoClass * required_type,MonoArray * ao,stackval * sp,gboolean needs_typecheck)790 ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, stackval *sp, gboolean needs_typecheck)
791 {
792 MonoClass *ac = ((MonoObject *) ao)->vtable->klass;
793
794 g_assert (ac->rank >= 1);
795
796 gint32 pos = ves_array_calculate_index (ao, sp, frame, TRUE);
797 if (frame->ex)
798 return NULL;
799
800 if (needs_typecheck && !mono_class_is_assignable_from (mono_object_class ((MonoObject *) ao)->element_class, required_type->element_class)) {
801 frame->ex = mono_get_exception_array_type_mismatch ();
802 FILL_IN_TRACE (frame->ex, frame);
803 return NULL;
804 }
805 gint32 esize = mono_array_element_size (ac);
806 return mono_array_addr_with_size (ao, esize, pos);
807 }
808
809 static void
interp_walk_stack_with_ctx(MonoInternalStackWalk func,MonoContext * ctx,MonoUnwindOptions options,void * user_data)810 interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data)
811 {
812 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
813
814 if (!context)
815 return;
816
817 InterpFrame *frame = context->current_frame;
818
819 while (frame) {
820 MonoStackFrameInfo fi;
821 memset (&fi, 0, sizeof (MonoStackFrameInfo));
822
823 /* TODO: hack to make some asserts happy. */
824 fi.ji = (MonoJitInfo *) frame->imethod;
825
826 if (frame->imethod)
827 fi.method = fi.actual_method = frame->imethod->method;
828
829 if (!fi.method || (fi.method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) || (fi.method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
830 fi.native_offset = -1;
831 fi.type = FRAME_TYPE_MANAGED_TO_NATIVE;
832 } else {
833 fi.type = FRAME_TYPE_MANAGED;
834 fi.native_offset = frame->ip - frame->imethod->code;
835 if (!fi.method->wrapper_type)
836 fi.managed = TRUE;
837 }
838
839 if (func (&fi, ctx, user_data))
840 return;
841 frame = frame->parent;
842 }
843 }
844
845 static MonoPIFunc mono_interp_enter_icall_trampoline = NULL;
846
build_args_from_sig(MonoMethodSignature * sig,InterpFrame * frame)847 static InterpMethodArguments* build_args_from_sig (MonoMethodSignature *sig, InterpFrame *frame)
848 {
849 InterpMethodArguments *margs = g_malloc0 (sizeof (InterpMethodArguments));
850
851 #ifdef TARGET_ARM
852 g_assert (mono_arm_eabi_supported ());
853 int i8_align = mono_arm_i8_align ();
854 #endif
855
856 #ifdef TARGET_WASM
857 margs->sig = sig;
858 #endif
859
860 if (sig->hasthis)
861 margs->ilen++;
862
863 for (int i = 0; i < sig->param_count; i++) {
864 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
865 switch (ptype) {
866 case MONO_TYPE_BOOLEAN:
867 case MONO_TYPE_CHAR:
868 case MONO_TYPE_I1:
869 case MONO_TYPE_U1:
870 case MONO_TYPE_I2:
871 case MONO_TYPE_U2:
872 case MONO_TYPE_I4:
873 case MONO_TYPE_U4:
874 case MONO_TYPE_I:
875 case MONO_TYPE_U:
876 case MONO_TYPE_PTR:
877 case MONO_TYPE_SZARRAY:
878 case MONO_TYPE_CLASS:
879 case MONO_TYPE_OBJECT:
880 case MONO_TYPE_STRING:
881 case MONO_TYPE_VALUETYPE:
882 case MONO_TYPE_GENERICINST:
883 #if SIZEOF_VOID_P == 8
884 case MONO_TYPE_I8:
885 case MONO_TYPE_U8:
886 #endif
887 margs->ilen++;
888 break;
889 #if SIZEOF_VOID_P == 4
890 case MONO_TYPE_I8:
891 case MONO_TYPE_U8:
892 #ifdef TARGET_ARM
893 /* pairs begin at even registers */
894 if (i8_align == 8 && margs->ilen & 1)
895 margs->ilen++;
896 #endif
897 margs->ilen += 2;
898 break;
899 #endif
900 case MONO_TYPE_R4:
901 #if SIZEOF_VOID_P == 8
902 case MONO_TYPE_R8:
903 #endif
904 margs->flen++;
905 break;
906 #if SIZEOF_VOID_P == 4
907 case MONO_TYPE_R8:
908 margs->flen += 2;
909 break;
910 #endif
911 default:
912 g_error ("build_args_from_sig: not implemented yet (1): 0x%x\n", ptype);
913 }
914 }
915
916 if (margs->ilen > 0)
917 margs->iargs = g_malloc0 (sizeof (gpointer) * margs->ilen);
918
919 if (margs->flen > 0)
920 margs->fargs = g_malloc0 (sizeof (double) * margs->flen);
921
922 if (margs->ilen > INTERP_ICALL_TRAMP_IARGS)
923 g_error ("build_args_from_sig: TODO, allocate gregs: %d\n", margs->ilen);
924
925 if (margs->flen > INTERP_ICALL_TRAMP_FARGS)
926 g_error ("build_args_from_sig: TODO, allocate fregs: %d\n", margs->flen);
927
928
929 size_t int_i = 0;
930 size_t int_f = 0;
931
932 if (sig->hasthis) {
933 margs->iargs [0] = frame->stack_args->data.p;
934 int_i++;
935 }
936
937 for (int i = 0; i < sig->param_count; i++) {
938 guint32 ptype = sig->params [i]->byref ? MONO_TYPE_PTR : sig->params [i]->type;
939 switch (ptype) {
940 case MONO_TYPE_BOOLEAN:
941 case MONO_TYPE_CHAR:
942 case MONO_TYPE_I1:
943 case MONO_TYPE_U1:
944 case MONO_TYPE_I2:
945 case MONO_TYPE_U2:
946 case MONO_TYPE_I4:
947 case MONO_TYPE_U4:
948 case MONO_TYPE_I:
949 case MONO_TYPE_U:
950 case MONO_TYPE_PTR:
951 case MONO_TYPE_SZARRAY:
952 case MONO_TYPE_CLASS:
953 case MONO_TYPE_OBJECT:
954 case MONO_TYPE_STRING:
955 case MONO_TYPE_VALUETYPE:
956 case MONO_TYPE_GENERICINST:
957 #if SIZEOF_VOID_P == 8
958 case MONO_TYPE_I8:
959 case MONO_TYPE_U8:
960 #endif
961 margs->iargs [int_i] = frame->stack_args [i].data.p;
962 #if DEBUG_INTERP
963 g_print ("build_args_from_sig: margs->iargs [%d]: %p (frame @ %d)\n", int_i, margs->iargs [int_i], i);
964 #endif
965 int_i++;
966 break;
967 #if SIZEOF_VOID_P == 4
968 case MONO_TYPE_I8:
969 case MONO_TYPE_U8: {
970 stackval *sarg = &frame->stack_args [i];
971 #ifdef TARGET_ARM
972 /* pairs begin at even registers */
973 if (i8_align == 8 && int_i & 1)
974 int_i++;
975 #endif
976 margs->iargs [int_i] = (gpointer) sarg->data.pair.lo;
977 int_i++;
978 margs->iargs [int_i] = (gpointer) sarg->data.pair.hi;
979 #if DEBUG_INTERP
980 g_print ("build_args_from_sig: margs->iargs [%d/%d]: 0x%016llx, hi=0x%08x lo=0x%08x (frame @ %d)\n", int_i - 1, int_i, *((guint64 *) &margs->iargs [int_i - 1]), sarg->data.pair.hi, sarg->data.pair.lo, i);
981 #endif
982 int_i++;
983 break;
984 }
985 #endif
986 case MONO_TYPE_R4:
987 case MONO_TYPE_R8:
988 if (ptype == MONO_TYPE_R4)
989 * (float *) &(margs->fargs [int_f]) = (float) frame->stack_args [i].data.f;
990 else
991 margs->fargs [int_f] = frame->stack_args [i].data.f;
992 #if DEBUG_INTERP
993 g_print ("build_args_from_sig: margs->fargs [%d]: %p (%f) (frame @ %d)\n", int_f, margs->fargs [int_f], margs->fargs [int_f], i);
994 #endif
995 #if SIZEOF_VOID_P == 4
996 int_f += 2;
997 #else
998 int_f++;
999 #endif
1000 break;
1001 default:
1002 g_error ("build_args_from_sig: not implemented yet (2): 0x%x\n", ptype);
1003 }
1004 }
1005
1006 switch (sig->ret->type) {
1007 case MONO_TYPE_BOOLEAN:
1008 case MONO_TYPE_CHAR:
1009 case MONO_TYPE_I1:
1010 case MONO_TYPE_U1:
1011 case MONO_TYPE_I2:
1012 case MONO_TYPE_U2:
1013 case MONO_TYPE_I4:
1014 case MONO_TYPE_U4:
1015 case MONO_TYPE_I:
1016 case MONO_TYPE_U:
1017 case MONO_TYPE_PTR:
1018 case MONO_TYPE_SZARRAY:
1019 case MONO_TYPE_CLASS:
1020 case MONO_TYPE_OBJECT:
1021 case MONO_TYPE_STRING:
1022 case MONO_TYPE_I8:
1023 case MONO_TYPE_U8:
1024 case MONO_TYPE_VALUETYPE:
1025 case MONO_TYPE_GENERICINST:
1026 margs->retval = &(frame->retval->data.p);
1027 margs->is_float_ret = 0;
1028 break;
1029 case MONO_TYPE_R4:
1030 case MONO_TYPE_R8:
1031 margs->retval = &(frame->retval->data.p);
1032 margs->is_float_ret = 1;
1033 break;
1034 case MONO_TYPE_VOID:
1035 margs->retval = NULL;
1036 break;
1037 default:
1038 g_error ("build_args_from_sig: ret type not implemented yet: 0x%x\n", sig->ret->type);
1039 }
1040
1041 return margs;
1042 }
1043
1044 static void
ves_pinvoke_method(InterpFrame * frame,MonoMethodSignature * sig,MonoFuncV addr,gboolean string_ctor,ThreadContext * context)1045 ves_pinvoke_method (InterpFrame *frame, MonoMethodSignature *sig, MonoFuncV addr, gboolean string_ctor, ThreadContext *context)
1046 {
1047 MonoLMFExt ext;
1048
1049 frame->ex = NULL;
1050
1051 g_assert (!frame->imethod);
1052 if (!mono_interp_enter_icall_trampoline) {
1053 if (mono_aot_only) {
1054 mono_interp_enter_icall_trampoline = mono_aot_get_trampoline ("enter_icall_trampoline");
1055 } else {
1056 MonoTrampInfo *info;
1057 mono_interp_enter_icall_trampoline = mono_arch_get_enter_icall_trampoline (&info);
1058 // TODO:
1059 // mono_tramp_info_register (info, NULL);
1060 }
1061 }
1062
1063 InterpMethodArguments *margs = build_args_from_sig (sig, frame);
1064 #if DEBUG_INTERP
1065 g_print ("ICALL: mono_interp_enter_icall_trampoline = %p, addr = %p\n", mono_interp_enter_icall_trampoline, addr);
1066 g_print ("margs(out): ilen=%d, flen=%d\n", margs->ilen, margs->flen);
1067 #endif
1068
1069 context->current_frame = frame;
1070
1071 interp_push_lmf (&ext, frame);
1072 mono_interp_enter_icall_trampoline (addr, margs);
1073 interp_pop_lmf (&ext);
1074
1075 if (*mono_thread_interruption_request_flag ()) {
1076 MonoException *exc = mono_thread_interruption_checkpoint ();
1077 if (exc) {
1078 frame->ex = exc;
1079 context->search_for_handler = 1;
1080 }
1081 }
1082
1083 if (!frame->ex && !MONO_TYPE_ISSTRUCT (sig->ret))
1084 stackval_from_data (sig->ret, frame->retval, (char*)&frame->retval->data.p, sig->pinvoke);
1085
1086 g_free (margs->iargs);
1087 g_free (margs->fargs);
1088 g_free (margs);
1089 }
1090
1091 static void
interp_init_delegate(MonoDelegate * del)1092 interp_init_delegate (MonoDelegate *del)
1093 {
1094 if (del->method)
1095 return;
1096 /* shouldn't need a write barrier because we don't write a MonoObject into the field */
1097 del->method = ((InterpMethod *) del->method_ptr)->method;
1098 }
1099
1100 /*
1101 * From the spec:
1102 * runtime specifies that the implementation of the method is automatically
1103 * provided by the runtime and is primarily used for the methods of delegates.
1104 */
1105 static void
ves_imethod(InterpFrame * frame,ThreadContext * context)1106 ves_imethod (InterpFrame *frame, ThreadContext *context)
1107 {
1108 MonoMethod *method = frame->imethod->method;
1109 const char *name = method->name;
1110 MonoObject *obj = (MonoObject*) frame->stack_args->data.p;
1111 MonoObject *isinst_obj;
1112 MonoError error;
1113
1114 mono_class_init (method->klass);
1115
1116 if (method->klass == mono_defaults.array_class) {
1117 if (!strcmp (method->name, "UnsafeMov")) {
1118 /* TODO: layout checks */
1119 MonoType *mt = mono_method_signature (method)->ret;
1120 stackval_from_data (mt, frame->retval, (char *) frame->stack_args, FALSE);
1121 return;
1122 }
1123 if (!strcmp (method->name, "UnsafeLoad")) {
1124 ves_array_get (frame, FALSE);
1125 return;
1126 }
1127 }
1128
1129 isinst_obj = mono_object_isinst_checked (obj, mono_defaults.array_class, &error);
1130 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1131 if (obj && isinst_obj) {
1132 if (*name == 'S' && (strcmp (name, "Set") == 0)) {
1133 ves_array_set (frame);
1134 return;
1135 }
1136 if (*name == 'G' && (strcmp (name, "Get") == 0)) {
1137 ves_array_get (frame, TRUE);
1138 return;
1139 }
1140 }
1141
1142 g_error ("Don't know how to exec runtime method %s.%s::%s",
1143 method->klass->name_space, method->klass->name,
1144 method->name);
1145 }
1146
1147 #if DEBUG_INTERP
1148 static char*
dump_stack(stackval * stack,stackval * sp)1149 dump_stack (stackval *stack, stackval *sp)
1150 {
1151 stackval *s = stack;
1152 GString *str = g_string_new ("");
1153
1154 if (sp == stack)
1155 return g_string_free (str, FALSE);
1156
1157 while (s < sp) {
1158 g_string_append_printf (str, "[%p (%lld)] ", s->data.l, s->data.l);
1159 ++s;
1160 }
1161 return g_string_free (str, FALSE);
1162 }
1163 #endif
1164
1165 static void
dump_stackval(GString * str,stackval * s,MonoType * type)1166 dump_stackval (GString *str, stackval *s, MonoType *type)
1167 {
1168 switch (type->type) {
1169 case MONO_TYPE_I1:
1170 case MONO_TYPE_U1:
1171 case MONO_TYPE_I2:
1172 case MONO_TYPE_U2:
1173 case MONO_TYPE_I4:
1174 case MONO_TYPE_U4:
1175 case MONO_TYPE_CHAR:
1176 case MONO_TYPE_BOOLEAN:
1177 g_string_append_printf (str, "[%d] ", s->data.i);
1178 break;
1179 case MONO_TYPE_STRING:
1180 case MONO_TYPE_SZARRAY:
1181 case MONO_TYPE_CLASS:
1182 case MONO_TYPE_OBJECT:
1183 case MONO_TYPE_ARRAY:
1184 case MONO_TYPE_PTR:
1185 case MONO_TYPE_I:
1186 case MONO_TYPE_U:
1187 g_string_append_printf (str, "[%p] ", s->data.p);
1188 break;
1189 case MONO_TYPE_VALUETYPE:
1190 if (type->data.klass->enumtype)
1191 g_string_append_printf (str, "[%d] ", s->data.i);
1192 else
1193 g_string_append_printf (str, "[vt:%p] ", s->data.p);
1194 break;
1195 case MONO_TYPE_R4:
1196 case MONO_TYPE_R8:
1197 g_string_append_printf (str, "[%g] ", s->data.f);
1198 break;
1199 case MONO_TYPE_I8:
1200 case MONO_TYPE_U8:
1201 default: {
1202 GString *res = g_string_new ("");
1203 mono_type_get_desc (res, type, TRUE);
1204 g_string_append_printf (str, "[{%s} %lld/0x%0llx] ", res->str, s->data.l, s->data.l);
1205 g_string_free (res, TRUE);
1206 break;
1207 }
1208 }
1209 }
1210
1211 #if DEBUG_INTERP
1212 static char*
dump_retval(InterpFrame * inv)1213 dump_retval (InterpFrame *inv)
1214 {
1215 GString *str = g_string_new ("");
1216 MonoType *ret = mono_method_signature (inv->imethod->method)->ret;
1217
1218 if (ret->type != MONO_TYPE_VOID)
1219 dump_stackval (str, inv->retval, ret);
1220
1221 return g_string_free (str, FALSE);
1222 }
1223 #endif
1224
1225 static char*
dump_args(InterpFrame * inv)1226 dump_args (InterpFrame *inv)
1227 {
1228 GString *str = g_string_new ("");
1229 int i;
1230 MonoMethodSignature *signature = mono_method_signature (inv->imethod->method);
1231
1232 if (signature->param_count == 0 && !signature->hasthis)
1233 return g_string_free (str, FALSE);
1234
1235 if (signature->hasthis) {
1236 MonoMethod *method = inv->imethod->method;
1237 dump_stackval (str, inv->stack_args, &method->klass->byval_arg);
1238 }
1239
1240 for (i = 0; i < signature->param_count; ++i)
1241 dump_stackval (str, inv->stack_args + (!!signature->hasthis) + i, signature->params [i]);
1242
1243 return g_string_free (str, FALSE);
1244 }
1245
1246 static char*
dump_frame(InterpFrame * inv)1247 dump_frame (InterpFrame *inv)
1248 {
1249 GString *str = g_string_new ("");
1250 int i;
1251 char *args;
1252 MonoError error;
1253
1254 for (i = 0; inv; inv = inv->parent) {
1255 if (inv->imethod != NULL) {
1256 MonoMethod *method = inv->imethod->method;
1257 MonoClass *k;
1258
1259 int codep = 0;
1260 const char * opname = "";
1261 char *name;
1262 gchar *source = NULL;
1263
1264 k = method->klass;
1265
1266 if ((method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
1267 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) == 0) {
1268 MonoMethodHeader *hd = mono_method_get_header_checked (method, &error);
1269 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1270
1271 if (hd != NULL) {
1272 if (inv->ip) {
1273 opname = mono_interp_opname [*inv->ip];
1274 codep = inv->ip - inv->imethod->code;
1275 source = g_strdup_printf ("%s:%d // (TODO: proper stacktrace)", method->name, codep);
1276 } else
1277 opname = "";
1278
1279 #if 0
1280 MonoDebugSourceLocation *minfo = mono_debug_lookup_method (method);
1281 source = mono_debug_method_lookup_location (minfo, codep);
1282 #endif
1283 mono_metadata_free_mh (hd);
1284 }
1285 }
1286 args = dump_args (inv);
1287 name = mono_method_full_name (method, TRUE);
1288 if (source)
1289 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s) at %s\n", i, codep, opname, name, args, source);
1290 else
1291 g_string_append_printf (str, "#%d: 0x%05x %-10s in %s (%s)\n", i, codep, opname, name, args);
1292 g_free (name);
1293 g_free (args);
1294 g_free (source);
1295 ++i;
1296 }
1297 }
1298 return g_string_free (str, FALSE);
1299 }
1300
1301 static MonoArray *
get_trace_ips(MonoDomain * domain,InterpFrame * top)1302 get_trace_ips (MonoDomain *domain, InterpFrame *top)
1303 {
1304 int i;
1305 MonoArray *res;
1306 InterpFrame *inv;
1307 MonoError error;
1308
1309 for (i = 0, inv = top; inv; inv = inv->parent)
1310 if (inv->imethod != NULL)
1311 ++i;
1312
1313 res = mono_array_new_checked (domain, mono_defaults.int_class, 3 * i, &error);
1314 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
1315
1316 for (i = 0, inv = top; inv; inv = inv->parent)
1317 if (inv->imethod != NULL) {
1318 mono_array_set (res, gpointer, i, inv->imethod);
1319 ++i;
1320 mono_array_set (res, gpointer, i, (gpointer)inv->ip);
1321 ++i;
1322 mono_array_set (res, gpointer, i, NULL);
1323 ++i;
1324 }
1325
1326 return res;
1327 }
1328
1329
1330 #define MYGUINT64_MAX 18446744073709551615ULL
1331 #define MYGINT64_MAX 9223372036854775807LL
1332 #define MYGINT64_MIN (-MYGINT64_MAX -1LL)
1333
1334 #define MYGUINT32_MAX 4294967295U
1335 #define MYGINT32_MAX 2147483647
1336 #define MYGINT32_MIN (-MYGINT32_MAX -1)
1337
1338 #define CHECK_ADD_OVERFLOW(a,b) \
1339 (gint32)(b) >= 0 ? (gint32)(MYGINT32_MAX) - (gint32)(b) < (gint32)(a) ? -1 : 0 \
1340 : (gint32)(MYGINT32_MIN) - (gint32)(b) > (gint32)(a) ? +1 : 0
1341
1342 #define CHECK_SUB_OVERFLOW(a,b) \
1343 (gint32)(b) < 0 ? (gint32)(MYGINT32_MAX) + (gint32)(b) < (gint32)(a) ? -1 : 0 \
1344 : (gint32)(MYGINT32_MIN) + (gint32)(b) > (gint32)(a) ? +1 : 0
1345
1346 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1347 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1348
1349 #define CHECK_SUB_OVERFLOW_UN(a,b) \
1350 (guint32)(a) < (guint32)(b) ? -1 : 0
1351
1352 #define CHECK_ADD_OVERFLOW64(a,b) \
1353 (gint64)(b) >= 0 ? (gint64)(MYGINT64_MAX) - (gint64)(b) < (gint64)(a) ? -1 : 0 \
1354 : (gint64)(MYGINT64_MIN) - (gint64)(b) > (gint64)(a) ? +1 : 0
1355
1356 #define CHECK_SUB_OVERFLOW64(a,b) \
1357 (gint64)(b) < 0 ? (gint64)(MYGINT64_MAX) + (gint64)(b) < (gint64)(a) ? -1 : 0 \
1358 : (gint64)(MYGINT64_MIN) + (gint64)(b) > (gint64)(a) ? +1 : 0
1359
1360 #define CHECK_ADD_OVERFLOW64_UN(a,b) \
1361 (guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a) ? -1 : 0
1362
1363 #define CHECK_SUB_OVERFLOW64_UN(a,b) \
1364 (guint64)(a) < (guint64)(b) ? -1 : 0
1365
1366 #if SIZEOF_VOID_P == 4
1367 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW(a,b)
1368 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW_UN(a,b)
1369 #else
1370 #define CHECK_ADD_OVERFLOW_NAT(a,b) CHECK_ADD_OVERFLOW64(a,b)
1371 #define CHECK_ADD_OVERFLOW_NAT_UN(a,b) CHECK_ADD_OVERFLOW64_UN(a,b)
1372 #endif
1373
1374 /* Resolves to TRUE if the operands would overflow */
1375 #define CHECK_MUL_OVERFLOW(a,b) \
1376 ((gint32)(a) == 0) || ((gint32)(b) == 0) ? 0 : \
1377 (((gint32)(a) > 0) && ((gint32)(b) == -1)) ? FALSE : \
1378 (((gint32)(a) < 0) && ((gint32)(b) == -1)) ? (a == - MYGINT32_MAX) : \
1379 (((gint32)(a) > 0) && ((gint32)(b) > 0)) ? (gint32)(a) > ((MYGINT32_MAX) / (gint32)(b)) : \
1380 (((gint32)(a) > 0) && ((gint32)(b) < 0)) ? (gint32)(a) > ((MYGINT32_MIN) / (gint32)(b)) : \
1381 (((gint32)(a) < 0) && ((gint32)(b) > 0)) ? (gint32)(a) < ((MYGINT32_MIN) / (gint32)(b)) : \
1382 (gint32)(a) < ((MYGINT32_MAX) / (gint32)(b))
1383
1384 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1385 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1386 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1387
1388 #define CHECK_MUL_OVERFLOW64(a,b) \
1389 ((gint64)(a) == 0) || ((gint64)(b) == 0) ? 0 : \
1390 (((gint64)(a) > 0) && ((gint64)(b) == -1)) ? FALSE : \
1391 (((gint64)(a) < 0) && ((gint64)(b) == -1)) ? (a == - MYGINT64_MAX) : \
1392 (((gint64)(a) > 0) && ((gint64)(b) > 0)) ? (gint64)(a) > ((MYGINT64_MAX) / (gint64)(b)) : \
1393 (((gint64)(a) > 0) && ((gint64)(b) < 0)) ? (gint64)(a) > ((MYGINT64_MIN) / (gint64)(b)) : \
1394 (((gint64)(a) < 0) && ((gint64)(b) > 0)) ? (gint64)(a) < ((MYGINT64_MIN) / (gint64)(b)) : \
1395 (gint64)(a) < ((MYGINT64_MAX) / (gint64)(b))
1396
1397 #define CHECK_MUL_OVERFLOW64_UN(a,b) \
1398 ((guint64)(a) == 0) || ((guint64)(b) == 0) ? 0 : \
1399 (guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a))
1400
1401 #if SIZEOF_VOID_P == 4
1402 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW(a,b)
1403 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW_UN(a,b)
1404 #else
1405 #define CHECK_MUL_OVERFLOW_NAT(a,b) CHECK_MUL_OVERFLOW64(a,b)
1406 #define CHECK_MUL_OVERFLOW_NAT_UN(a,b) CHECK_MUL_OVERFLOW64_UN(a,b)
1407 #endif
1408
1409 static MonoObject*
interp_runtime_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc,MonoError * error)1410 interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
1411 {
1412 InterpFrame frame, *old_frame;
1413 ThreadContext * volatile context = mono_native_tls_get_value (thread_context_id);
1414 MonoMethodSignature *sig = mono_method_signature (method);
1415 MonoClass *klass = mono_class_from_mono_type (sig->ret);
1416 stackval result;
1417 stackval *args;
1418 ThreadContext context_struct;
1419
1420 error_init (error);
1421 if (exc)
1422 *exc = NULL;
1423
1424 frame.ex = NULL;
1425
1426 if (context == NULL) {
1427 context = &context_struct;
1428 memset (context, 0, sizeof (ThreadContext));
1429 set_context (context);
1430 } else {
1431 old_frame = context->current_frame;
1432 }
1433
1434 MonoDomain *domain = mono_domain_get ();
1435
1436 MonoMethod *invoke_wrapper = mono_marshal_get_runtime_invoke_full (method, FALSE, TRUE);
1437
1438 //* <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
1439
1440 result.data.vt = alloca (mono_class_instance_size (klass));
1441 args = alloca (sizeof (stackval) * 4);
1442
1443 if (sig->hasthis)
1444 args [0].data.p = obj;
1445 else
1446 args [0].data.p = NULL;
1447 args [1].data.p = params;
1448 args [2].data.p = exc;
1449 args [3].data.p = method;
1450
1451 INIT_FRAME (&frame, context->current_frame, args, &result, domain, invoke_wrapper, error);
1452
1453 if (exc)
1454 frame.invoke_trap = 1;
1455
1456 interp_exec_method (&frame, context);
1457
1458 if (context == &context_struct)
1459 set_context (NULL);
1460 else
1461 context->current_frame = old_frame;
1462
1463 if (frame.ex) {
1464 if (exc) {
1465 *exc = (MonoObject*) frame.ex;
1466 return NULL;
1467 }
1468 mono_error_set_exception_instance (error, frame.ex);
1469 return NULL;
1470 }
1471 return result.data.p;
1472 }
1473
1474 typedef struct {
1475 InterpMethod *rmethod;
1476 gpointer this_arg;
1477 gpointer res;
1478 gpointer args [16];
1479 gpointer *many_args;
1480 } InterpEntryData;
1481
1482 /* Main function for entering the interpreter from compiled code */
1483 static void
interp_entry(InterpEntryData * data)1484 interp_entry (InterpEntryData *data)
1485 {
1486 InterpFrame frame;
1487 InterpMethod *rmethod = data->rmethod;
1488 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
1489 ThreadContext context_struct;
1490 InterpFrame *old_frame;
1491 stackval result;
1492 stackval *args;
1493 MonoMethod *method;
1494 MonoMethodSignature *sig;
1495 MonoType *type;
1496 int i;
1497
1498 method = rmethod->method;
1499 sig = mono_method_signature (method);
1500
1501 // FIXME: Optimize this
1502
1503 //printf ("%s\n", mono_method_full_name (method, 1));
1504
1505 frame.ex = NULL;
1506 if (context == NULL) {
1507 context = &context_struct;
1508 memset (context, 0, sizeof (ThreadContext));
1509 set_context (context);
1510 } else {
1511 old_frame = context->current_frame;
1512 }
1513
1514 args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
1515 if (sig->hasthis)
1516 args [0].data.p = data->this_arg;
1517
1518 gpointer *params;
1519 if (data->many_args)
1520 params = data->many_args;
1521 else
1522 params = data->args;
1523 for (i = 0; i < sig->param_count; ++i) {
1524 int a_index = i + (sig->hasthis ? 1 : 0);
1525 if (sig->params [i]->byref) {
1526 args [a_index].data.p = params [i];
1527 continue;
1528 }
1529 type = rmethod->param_types [i];
1530 switch (type->type) {
1531 case MONO_TYPE_U1:
1532 case MONO_TYPE_I1:
1533 args [a_index].data.i = *(MonoBoolean*)params [i];
1534 break;
1535 case MONO_TYPE_U2:
1536 case MONO_TYPE_I2:
1537 args [a_index].data.i = *(gint16*)params [i];
1538 break;
1539 case MONO_TYPE_U:
1540 #if SIZEOF_VOID_P == 4
1541 args [a_index].data.p = GINT_TO_POINTER (*(guint32*)params [i]);
1542 #else
1543 args [a_index].data.p = GINT_TO_POINTER (*(guint64*)params [i]);
1544 #endif
1545 break;
1546 case MONO_TYPE_I:
1547 #if SIZEOF_VOID_P == 4
1548 args [a_index].data.p = GINT_TO_POINTER (*(gint32*)params [i]);
1549 #else
1550 args [a_index].data.p = GINT_TO_POINTER (*(gint64*)params [i]);
1551 #endif
1552 break;
1553 case MONO_TYPE_U4:
1554 args [a_index].data.i = *(guint32*)params [i];
1555 break;
1556 case MONO_TYPE_I4:
1557 args [a_index].data.i = *(gint32*)params [i];
1558 break;
1559 case MONO_TYPE_U8:
1560 args [a_index].data.l = *(guint64*)params [i];
1561 break;
1562 case MONO_TYPE_I8:
1563 args [a_index].data.l = *(gint64*)params [i];
1564 break;
1565 case MONO_TYPE_PTR:
1566 case MONO_TYPE_OBJECT:
1567 args [a_index].data.p = *(MonoObject**)params [i];
1568 break;
1569 case MONO_TYPE_VALUETYPE:
1570 args [a_index].data.p = params [i];
1571 break;
1572 case MONO_TYPE_GENERICINST:
1573 if (MONO_TYPE_IS_REFERENCE (type))
1574 args [a_index].data.p = params [i];
1575 else
1576 args [a_index].data.vt = params [i];
1577 break;
1578 default:
1579 printf ("%s\n", mono_type_full_name (sig->params [i]));
1580 NOT_IMPLEMENTED;
1581 break;
1582 }
1583 }
1584
1585 init_frame (&frame, NULL, data->rmethod, args, &result);
1586
1587 type = rmethod->rtype;
1588 switch (type->type) {
1589 case MONO_TYPE_GENERICINST:
1590 if (!MONO_TYPE_IS_REFERENCE (type))
1591 frame.retval->data.vt = data->res;
1592 break;
1593 case MONO_TYPE_VALUETYPE:
1594 frame.retval->data.vt = data->res;
1595 break;
1596 default:
1597 break;
1598 }
1599
1600 interp_exec_method (&frame, context);
1601 if (context == &context_struct)
1602 set_context (NULL);
1603 else
1604 context->current_frame = old_frame;
1605
1606 // FIXME:
1607 g_assert (frame.ex == NULL);
1608
1609 type = rmethod->rtype;
1610 switch (type->type) {
1611 case MONO_TYPE_VOID:
1612 break;
1613 case MONO_TYPE_I1:
1614 *(gint8*)data->res = frame.retval->data.i;
1615 break;
1616 case MONO_TYPE_U1:
1617 *(guint8*)data->res = frame.retval->data.i;
1618 break;
1619 case MONO_TYPE_I2:
1620 *(gint16*)data->res = frame.retval->data.i;
1621 break;
1622 case MONO_TYPE_U2:
1623 *(guint16*)data->res = frame.retval->data.i;
1624 break;
1625 case MONO_TYPE_I4:
1626 *(gint32*)data->res = frame.retval->data.i;
1627 break;
1628 case MONO_TYPE_U4:
1629 *(guint64*)data->res = frame.retval->data.i;
1630 break;
1631 case MONO_TYPE_I8:
1632 *(gint64*)data->res = frame.retval->data.i;
1633 break;
1634 case MONO_TYPE_U8:
1635 *(guint64*)data->res = frame.retval->data.i;
1636 break;
1637 case MONO_TYPE_I:
1638 #if SIZEOF_VOID_P == 8
1639 *(gint64*)data->res = (gint64)frame.retval->data.p;
1640 #else
1641 *(gint32*)data->res = (gint32)frame.retval->data.p;
1642 #endif
1643 break;
1644 case MONO_TYPE_U:
1645 #if SIZEOF_VOID_P == 8
1646 *(guint64*)data->res = (guint64)frame.retval->data.p;
1647 #else
1648 *(guint32*)data->res = (guint32)frame.retval->data.p;
1649 #endif
1650 break;
1651 case MONO_TYPE_OBJECT:
1652 /* No need for a write barrier */
1653 *(MonoObject**)data->res = (MonoObject*)frame.retval->data.p;
1654 break;
1655 case MONO_TYPE_GENERICINST:
1656 if (MONO_TYPE_IS_REFERENCE (type)) {
1657 *(MonoObject**)data->res = *(MonoObject**)frame.retval->data.p;
1658 } else {
1659 /* Already set before the call */
1660 }
1661 break;
1662 case MONO_TYPE_VALUETYPE:
1663 /* Already set before the call */
1664 break;
1665 default:
1666 printf ("%s\n", mono_type_full_name (sig->ret));
1667 NOT_IMPLEMENTED;
1668 break;
1669 }
1670 }
1671
1672 static stackval *
do_icall(ThreadContext * context,int op,stackval * sp,gpointer ptr)1673 do_icall (ThreadContext *context, int op, stackval *sp, gpointer ptr)
1674 {
1675 MonoLMFExt ext;
1676 interp_push_lmf (&ext, context->current_frame);
1677
1678 switch (op) {
1679 case MINT_ICALL_V_V: {
1680 void (*func)(void) = ptr;
1681 func ();
1682 break;
1683 }
1684 case MINT_ICALL_V_P: {
1685 gpointer (*func)(void) = ptr;
1686 sp++;
1687 sp [-1].data.p = func ();
1688 break;
1689 }
1690 case MINT_ICALL_P_V: {
1691 void (*func)(gpointer) = ptr;
1692 func (sp [-1].data.p);
1693 sp --;
1694 break;
1695 }
1696 case MINT_ICALL_P_P: {
1697 gpointer (*func)(gpointer) = ptr;
1698 sp [-1].data.p = func (sp [-1].data.p);
1699 break;
1700 }
1701 case MINT_ICALL_PP_V: {
1702 void (*func)(gpointer,gpointer) = ptr;
1703 sp -= 2;
1704 func (sp [0].data.p, sp [1].data.p);
1705 break;
1706 }
1707 case MINT_ICALL_PI_V: {
1708 void (*func)(gpointer,int) = ptr;
1709 sp -= 2;
1710 func (sp [0].data.p, sp [1].data.i);
1711 break;
1712 }
1713 case MINT_ICALL_PP_P: {
1714 gpointer (*func)(gpointer,gpointer) = ptr;
1715 --sp;
1716 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.p);
1717 break;
1718 }
1719 case MINT_ICALL_PI_P: {
1720 gpointer (*func)(gpointer,int) = ptr;
1721 --sp;
1722 sp [-1].data.p = func (sp [-1].data.p, sp [0].data.i);
1723 break;
1724 }
1725 case MINT_ICALL_PPP_V: {
1726 void (*func)(gpointer,gpointer,gpointer) = ptr;
1727 sp -= 3;
1728 func (sp [0].data.p, sp [1].data.p, sp [2].data.p);
1729 break;
1730 }
1731 case MINT_ICALL_PPI_V: {
1732 void (*func)(gpointer,gpointer,int) = ptr;
1733 sp -= 3;
1734 func (sp [0].data.p, sp [1].data.p, sp [2].data.i);
1735 break;
1736 }
1737 default:
1738 g_assert_not_reached ();
1739 }
1740
1741 interp_pop_lmf (&ext);
1742 return sp;
1743 }
1744
1745 static stackval *
do_jit_call(stackval * sp,unsigned char * vt_sp,ThreadContext * context,InterpFrame * frame,InterpMethod * rmethod)1746 do_jit_call (stackval *sp, unsigned char *vt_sp, ThreadContext *context, InterpFrame *frame, InterpMethod *rmethod)
1747 {
1748 MonoMethodSignature *sig;
1749 MonoFtnDesc ftndesc;
1750 guint8 res_buf [256];
1751 MonoType *type;
1752 MonoLMFExt ext;
1753
1754 //printf ("%s\n", mono_method_full_name (rmethod->method, 1));
1755
1756 /*
1757 * Call JITted code through a gsharedvt_out wrapper. These wrappers receive every argument
1758 * by ref and return a return value using an explicit return value argument.
1759 */
1760 if (!rmethod->jit_wrapper) {
1761 MonoMethod *method = rmethod->method;
1762 MonoError error;
1763
1764 sig = mono_method_signature (method);
1765 g_assert (sig);
1766
1767 MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
1768 //printf ("J: %s %s\n", mono_method_full_name (method, 1), mono_method_full_name (wrapper, 1));
1769
1770 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, &error);
1771 mono_error_assert_ok (&error);
1772
1773 gpointer addr = mono_jit_compile_method_jit_only (method, &error);
1774 g_assert (addr);
1775 mono_error_assert_ok (&error);
1776
1777 rmethod->jit_addr = addr;
1778 rmethod->jit_sig = sig;
1779 mono_memory_barrier ();
1780 rmethod->jit_wrapper = jit_wrapper;
1781
1782 } else {
1783 sig = rmethod->jit_sig;
1784 }
1785
1786 sp -= sig->param_count;
1787 if (sig->hasthis)
1788 --sp;
1789
1790 ftndesc.addr = rmethod->jit_addr;
1791 ftndesc.arg = NULL;
1792
1793 // FIXME: Optimize this
1794
1795 gpointer args [32];
1796 int pindex = 0;
1797 int stack_index = 0;
1798 if (rmethod->hasthis) {
1799 args [pindex ++] = sp [0].data.p;
1800 stack_index ++;
1801 }
1802 type = rmethod->rtype;
1803 if (type->type != MONO_TYPE_VOID) {
1804 if (MONO_TYPE_ISSTRUCT (type))
1805 args [pindex ++] = vt_sp;
1806 else
1807 args [pindex ++] = res_buf;
1808 }
1809 for (int i = 0; i < rmethod->param_count; ++i) {
1810 MonoType *t = rmethod->param_types [i];
1811 stackval *sval = &sp [stack_index + i];
1812 if (sig->params [i]->byref) {
1813 args [pindex ++] = sval->data.p;
1814 } else if (MONO_TYPE_ISSTRUCT (t)) {
1815 args [pindex ++] = sval->data.p;
1816 } else if (MONO_TYPE_IS_REFERENCE (t)) {
1817 args [pindex ++] = &sval->data.p;
1818 } else {
1819 switch (t->type) {
1820 case MONO_TYPE_I1:
1821 case MONO_TYPE_U1:
1822 case MONO_TYPE_I2:
1823 case MONO_TYPE_U2:
1824 case MONO_TYPE_I4:
1825 case MONO_TYPE_U4:
1826 case MONO_TYPE_VALUETYPE:
1827 args [pindex ++] = &sval->data.i;
1828 break;
1829 case MONO_TYPE_PTR:
1830 case MONO_TYPE_FNPTR:
1831 case MONO_TYPE_I:
1832 case MONO_TYPE_U:
1833 case MONO_TYPE_OBJECT:
1834 args [pindex ++] = &sval->data.p;
1835 break;
1836 case MONO_TYPE_I8:
1837 case MONO_TYPE_U8:
1838 args [pindex ++] = &sval->data.l;
1839 break;
1840 default:
1841 printf ("%s\n", mono_type_full_name (t));
1842 g_assert_not_reached ();
1843 }
1844 }
1845 }
1846
1847 interp_push_lmf (&ext, frame);
1848
1849 switch (pindex) {
1850 case 0: {
1851 void (*func)(gpointer) = rmethod->jit_wrapper;
1852
1853 func (&ftndesc);
1854 break;
1855 }
1856 case 1: {
1857 void (*func)(gpointer, gpointer) = rmethod->jit_wrapper;
1858
1859 func (args [0], &ftndesc);
1860 break;
1861 }
1862 case 2: {
1863 void (*func)(gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1864
1865 func (args [0], args [1], &ftndesc);
1866 break;
1867 }
1868 case 3: {
1869 void (*func)(gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1870
1871 func (args [0], args [1], args [2], &ftndesc);
1872 break;
1873 }
1874 case 4: {
1875 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1876
1877 func (args [0], args [1], args [2], args [3], &ftndesc);
1878 break;
1879 }
1880 case 5: {
1881 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1882
1883 func (args [0], args [1], args [2], args [3], args [4], &ftndesc);
1884 break;
1885 }
1886 case 6: {
1887 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1888
1889 func (args [0], args [1], args [2], args [3], args [4], args [5], &ftndesc);
1890 break;
1891 }
1892 case 7: {
1893 void (*func)(gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer, gpointer) = rmethod->jit_wrapper;
1894
1895 func (args [0], args [1], args [2], args [3], args [4], args [5], args [6], &ftndesc);
1896 break;
1897 }
1898 default:
1899 g_assert_not_reached ();
1900 break;
1901 }
1902
1903 interp_pop_lmf (&ext);
1904
1905 MonoType *rtype = rmethod->rtype;
1906 switch (rtype->type) {
1907 case MONO_TYPE_VOID:
1908 case MONO_TYPE_OBJECT:
1909 case MONO_TYPE_STRING:
1910 case MONO_TYPE_CLASS:
1911 case MONO_TYPE_ARRAY:
1912 case MONO_TYPE_SZARRAY:
1913 case MONO_TYPE_I:
1914 case MONO_TYPE_U:
1915 sp->data.p = *(gpointer*)res_buf;
1916 break;
1917 case MONO_TYPE_I1:
1918 sp->data.i = *(gint8*)res_buf;
1919 break;
1920 case MONO_TYPE_U1:
1921 sp->data.i = *(guint8*)res_buf;
1922 break;
1923 case MONO_TYPE_I2:
1924 sp->data.i = *(gint16*)res_buf;
1925 break;
1926 case MONO_TYPE_U2:
1927 sp->data.i = *(guint16*)res_buf;
1928 break;
1929 case MONO_TYPE_I4:
1930 sp->data.i = *(gint32*)res_buf;
1931 break;
1932 case MONO_TYPE_U4:
1933 sp->data.i = *(guint32*)res_buf;
1934 break;
1935 case MONO_TYPE_VALUETYPE:
1936 /* The result was written to vt_sp */
1937 sp->data.p = vt_sp;
1938 break;
1939 case MONO_TYPE_GENERICINST:
1940 if (MONO_TYPE_IS_REFERENCE (rtype)) {
1941 sp->data.p = *(gpointer*)res_buf;
1942 } else {
1943 /* The result was written to vt_sp */
1944 sp->data.p = vt_sp;
1945 }
1946 break;
1947 default:
1948 g_print ("%s\n", mono_type_full_name (rtype));
1949 g_assert_not_reached ();
1950 break;
1951 }
1952
1953 return sp;
1954 }
1955
1956 static void
do_debugger_tramp(void (* tramp)(void),InterpFrame * frame)1957 do_debugger_tramp (void (*tramp) (void), InterpFrame *frame)
1958 {
1959 MonoLMFExt ext;
1960 interp_push_lmf (&ext, frame);
1961 tramp ();
1962 interp_pop_lmf (&ext);
1963 }
1964
1965 static void
do_transform_method(InterpFrame * frame,ThreadContext * context)1966 do_transform_method (InterpFrame *frame, ThreadContext *context)
1967 {
1968 MonoLMFExt ext;
1969
1970 /* Use the parent frame as the current frame is not complete yet */
1971 interp_push_lmf (&ext, frame->parent);
1972
1973 frame->ex = mono_interp_transform_method (frame->imethod, context, frame);
1974
1975 interp_pop_lmf (&ext);
1976 }
1977
1978 /*
1979 * These functions are the entry points into the interpreter from compiled code.
1980 * They are called by the interp_in wrappers. They have the following signature:
1981 * void (<optional this_arg>, <optional retval pointer>, <arg1>, ..., <argn>, <method ptr>)
1982 * They pack up their arguments into an InterpEntryData structure and call interp_entry ().
1983 * It would be possible for the wrappers to pack up the arguments etc, but that would make them bigger, and there are
1984 * more wrappers then these functions.
1985 * this/static * ret/void * 16 arguments -> 64 functions.
1986 */
1987
1988 #define MAX_INTERP_ENTRY_ARGS 8
1989
1990 #define INTERP_ENTRY_BASE(_method, _this_arg, _res) \
1991 InterpEntryData data; \
1992 (data).rmethod = (_method); \
1993 (data).res = (_res); \
1994 (data).this_arg = (_this_arg); \
1995 (data).many_args = NULL;
1996
1997 #define INTERP_ENTRY0(_this_arg, _res, _method) { \
1998 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
1999 interp_entry (&data); \
2000 }
2001 #define INTERP_ENTRY1(_this_arg, _res, _method) { \
2002 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2003 (data).args [0] = arg1; \
2004 interp_entry (&data); \
2005 }
2006 #define INTERP_ENTRY2(_this_arg, _res, _method) { \
2007 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2008 (data).args [0] = arg1; \
2009 (data).args [1] = arg2; \
2010 interp_entry (&data); \
2011 }
2012 #define INTERP_ENTRY3(_this_arg, _res, _method) { \
2013 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2014 (data).args [0] = arg1; \
2015 (data).args [1] = arg2; \
2016 (data).args [2] = arg3; \
2017 interp_entry (&data); \
2018 }
2019 #define INTERP_ENTRY4(_this_arg, _res, _method) { \
2020 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2021 (data).args [0] = arg1; \
2022 (data).args [1] = arg2; \
2023 (data).args [2] = arg3; \
2024 (data).args [3] = arg4; \
2025 interp_entry (&data); \
2026 }
2027 #define INTERP_ENTRY5(_this_arg, _res, _method) { \
2028 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2029 (data).args [0] = arg1; \
2030 (data).args [1] = arg2; \
2031 (data).args [2] = arg3; \
2032 (data).args [3] = arg4; \
2033 (data).args [4] = arg5; \
2034 interp_entry (&data); \
2035 }
2036 #define INTERP_ENTRY6(_this_arg, _res, _method) { \
2037 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2038 (data).args [0] = arg1; \
2039 (data).args [1] = arg2; \
2040 (data).args [2] = arg3; \
2041 (data).args [3] = arg4; \
2042 (data).args [4] = arg5; \
2043 (data).args [5] = arg6; \
2044 interp_entry (&data); \
2045 }
2046 #define INTERP_ENTRY7(_this_arg, _res, _method) { \
2047 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2048 (data).args [0] = arg1; \
2049 (data).args [1] = arg2; \
2050 (data).args [2] = arg3; \
2051 (data).args [3] = arg4; \
2052 (data).args [4] = arg5; \
2053 (data).args [5] = arg6; \
2054 (data).args [6] = arg7; \
2055 interp_entry (&data); \
2056 }
2057 #define INTERP_ENTRY8(_this_arg, _res, _method) { \
2058 INTERP_ENTRY_BASE (_method, _this_arg, _res); \
2059 (data).args [0] = arg1; \
2060 (data).args [1] = arg2; \
2061 (data).args [2] = arg3; \
2062 (data).args [3] = arg4; \
2063 (data).args [4] = arg5; \
2064 (data).args [5] = arg6; \
2065 (data).args [6] = arg7; \
2066 (data).args [7] = arg8; \
2067 interp_entry (&data); \
2068 }
2069
2070 #define ARGLIST0 InterpMethod *rmethod
2071 #define ARGLIST1 gpointer arg1, InterpMethod *rmethod
2072 #define ARGLIST2 gpointer arg1, gpointer arg2, InterpMethod *rmethod
2073 #define ARGLIST3 gpointer arg1, gpointer arg2, gpointer arg3, InterpMethod *rmethod
2074 #define ARGLIST4 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, InterpMethod *rmethod
2075 #define ARGLIST5 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, InterpMethod *rmethod
2076 #define ARGLIST6 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, InterpMethod *rmethod
2077 #define ARGLIST7 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, InterpMethod *rmethod
2078 #define ARGLIST8 gpointer arg1, gpointer arg2, gpointer arg3, gpointer arg4, gpointer arg5, gpointer arg6, gpointer arg7, gpointer arg8, InterpMethod *rmethod
2079
2080 static void interp_entry_static_0 (ARGLIST0) INTERP_ENTRY0 (NULL, NULL, rmethod)
2081 static void interp_entry_static_1 (ARGLIST1) INTERP_ENTRY1 (NULL, NULL, rmethod)
2082 static void interp_entry_static_2 (ARGLIST2) INTERP_ENTRY2 (NULL, NULL, rmethod)
2083 static void interp_entry_static_3 (ARGLIST3) INTERP_ENTRY3 (NULL, NULL, rmethod)
2084 static void interp_entry_static_4 (ARGLIST4) INTERP_ENTRY4 (NULL, NULL, rmethod)
2085 static void interp_entry_static_5 (ARGLIST5) INTERP_ENTRY5 (NULL, NULL, rmethod)
2086 static void interp_entry_static_6 (ARGLIST6) INTERP_ENTRY6 (NULL, NULL, rmethod)
2087 static void interp_entry_static_7 (ARGLIST7) INTERP_ENTRY7 (NULL, NULL, rmethod)
2088 static void interp_entry_static_8 (ARGLIST8) INTERP_ENTRY8 (NULL, NULL, rmethod)
2089 static void interp_entry_static_ret_0 (gpointer res, ARGLIST0) INTERP_ENTRY0 (NULL, res, rmethod)
2090 static void interp_entry_static_ret_1 (gpointer res, ARGLIST1) INTERP_ENTRY1 (NULL, res, rmethod)
2091 static void interp_entry_static_ret_2 (gpointer res, ARGLIST2) INTERP_ENTRY2 (NULL, res, rmethod)
2092 static void interp_entry_static_ret_3 (gpointer res, ARGLIST3) INTERP_ENTRY3 (NULL, res, rmethod)
2093 static void interp_entry_static_ret_4 (gpointer res, ARGLIST4) INTERP_ENTRY4 (NULL, res, rmethod)
2094 static void interp_entry_static_ret_5 (gpointer res, ARGLIST5) INTERP_ENTRY5 (NULL, res, rmethod)
2095 static void interp_entry_static_ret_6 (gpointer res, ARGLIST6) INTERP_ENTRY6 (NULL, res, rmethod)
2096 static void interp_entry_static_ret_7 (gpointer res, ARGLIST7) INTERP_ENTRY7 (NULL, res, rmethod)
2097 static void interp_entry_static_ret_8 (gpointer res, ARGLIST8) INTERP_ENTRY8 (NULL, res, rmethod)
2098 static void interp_entry_instance_0 (gpointer this_arg, ARGLIST0) INTERP_ENTRY0 (this_arg, NULL, rmethod)
2099 static void interp_entry_instance_1 (gpointer this_arg, ARGLIST1) INTERP_ENTRY1 (this_arg, NULL, rmethod)
2100 static void interp_entry_instance_2 (gpointer this_arg, ARGLIST2) INTERP_ENTRY2 (this_arg, NULL, rmethod)
2101 static void interp_entry_instance_3 (gpointer this_arg, ARGLIST3) INTERP_ENTRY3 (this_arg, NULL, rmethod)
2102 static void interp_entry_instance_4 (gpointer this_arg, ARGLIST4) INTERP_ENTRY4 (this_arg, NULL, rmethod)
2103 static void interp_entry_instance_5 (gpointer this_arg, ARGLIST5) INTERP_ENTRY5 (this_arg, NULL, rmethod)
2104 static void interp_entry_instance_6 (gpointer this_arg, ARGLIST6) INTERP_ENTRY6 (this_arg, NULL, rmethod)
2105 static void interp_entry_instance_7 (gpointer this_arg, ARGLIST7) INTERP_ENTRY7 (this_arg, NULL, rmethod)
2106 static void interp_entry_instance_8 (gpointer this_arg, ARGLIST8) INTERP_ENTRY8 (this_arg, NULL, rmethod)
2107 static void interp_entry_instance_ret_0 (gpointer this_arg, gpointer res, ARGLIST0) INTERP_ENTRY0 (this_arg, res, rmethod)
2108 static void interp_entry_instance_ret_1 (gpointer this_arg, gpointer res, ARGLIST1) INTERP_ENTRY1 (this_arg, res, rmethod)
2109 static void interp_entry_instance_ret_2 (gpointer this_arg, gpointer res, ARGLIST2) INTERP_ENTRY2 (this_arg, res, rmethod)
2110 static void interp_entry_instance_ret_3 (gpointer this_arg, gpointer res, ARGLIST3) INTERP_ENTRY3 (this_arg, res, rmethod)
2111 static void interp_entry_instance_ret_4 (gpointer this_arg, gpointer res, ARGLIST4) INTERP_ENTRY4 (this_arg, res, rmethod)
2112 static void interp_entry_instance_ret_5 (gpointer this_arg, gpointer res, ARGLIST5) INTERP_ENTRY5 (this_arg, res, rmethod)
2113 static void interp_entry_instance_ret_6 (gpointer this_arg, gpointer res, ARGLIST6) INTERP_ENTRY6 (this_arg, res, rmethod)
2114 static void interp_entry_instance_ret_7 (gpointer this_arg, gpointer res, ARGLIST7) INTERP_ENTRY7 (this_arg, res, rmethod)
2115 static void interp_entry_instance_ret_8 (gpointer this_arg, gpointer res, ARGLIST8) INTERP_ENTRY8 (this_arg, res, rmethod)
2116
2117 #define INTERP_ENTRY_FUNCLIST(type) interp_entry_ ## type ## _0, interp_entry_ ## type ## _1, interp_entry_ ## type ## _2, interp_entry_ ## type ## _3, interp_entry_ ## type ## _4, interp_entry_ ## type ## _5, interp_entry_ ## type ## _6, interp_entry_ ## type ## _7, interp_entry_ ## type ## _8
2118
2119 gpointer entry_funcs_static [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static) };
2120 gpointer entry_funcs_static_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (static_ret) };
2121 gpointer entry_funcs_instance [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance) };
2122 gpointer entry_funcs_instance_ret [MAX_INTERP_ENTRY_ARGS + 1] = { INTERP_ENTRY_FUNCLIST (instance_ret) };
2123
2124 /* General version for methods with more than MAX_INTERP_ENTRY_ARGS arguments */
2125 static void
interp_entry_general(gpointer this_arg,gpointer res,gpointer * args,gpointer rmethod)2126 interp_entry_general (gpointer this_arg, gpointer res, gpointer *args, gpointer rmethod)
2127 {
2128 INTERP_ENTRY_BASE (rmethod, this_arg, res);
2129 data.many_args = args;
2130 interp_entry (&data);
2131 }
2132
2133 /*
2134 * interp_create_method_pointer:
2135 *
2136 * Return a function pointer which can be used to call METHOD using the
2137 * interpreter. Return NULL for methods which are not supported.
2138 */
2139 static gpointer
interp_create_method_pointer(MonoMethod * method,MonoError * error)2140 interp_create_method_pointer (MonoMethod *method, MonoError *error)
2141 {
2142 gpointer addr;
2143 MonoMethodSignature *sig = mono_method_signature (method);
2144 MonoMethod *wrapper;
2145 InterpMethod *rmethod = mono_interp_get_imethod (mono_domain_get (), method, error);
2146
2147 /* HACK: method_ptr of delegate should point to a runtime method*/
2148 if (method->wrapper_type && method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2149 return rmethod;
2150
2151 if (rmethod->jit_entry)
2152 return rmethod->jit_entry;
2153 wrapper = mini_get_interp_in_wrapper (sig);
2154
2155 gpointer jit_wrapper = mono_jit_compile_method_jit_only (wrapper, error);
2156 if (!mono_error_ok (error))
2157 g_error ("couldn't compile wrapper \"%s\" for \"%s\" (error: %s)\n", mono_method_get_full_name (wrapper), mono_method_get_full_name (method), mono_error_get_message (error));
2158
2159 gpointer entry_func;
2160 if (sig->param_count > MAX_INTERP_ENTRY_ARGS) {
2161 entry_func = interp_entry_general;
2162 } else if (sig->hasthis) {
2163 if (sig->ret->type == MONO_TYPE_VOID)
2164 entry_func = entry_funcs_instance [sig->param_count];
2165 else
2166 entry_func = entry_funcs_instance_ret [sig->param_count];
2167 } else {
2168 if (sig->ret->type == MONO_TYPE_VOID)
2169 entry_func = entry_funcs_static [sig->param_count];
2170 else
2171 entry_func = entry_funcs_static_ret [sig->param_count];
2172 }
2173 g_assert (entry_func);
2174
2175 /* This is the argument passed to the interp_in wrapper by the static rgctx trampoline */
2176 MonoFtnDesc *ftndesc = g_new0 (MonoFtnDesc, 1);
2177 ftndesc->addr = entry_func;
2178 ftndesc->arg = rmethod;
2179 mono_error_assert_ok (error);
2180
2181 /*
2182 * The wrapper is called by compiled code, which doesn't pass the extra argument, so we pass it in the
2183 * rgctx register using a trampoline.
2184 */
2185
2186 if (mono_aot_only)
2187 addr = mono_aot_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
2188 else
2189 addr = mono_arch_get_static_rgctx_trampoline (ftndesc, jit_wrapper);
2190
2191 mono_memory_barrier ();
2192 rmethod->jit_entry = addr;
2193
2194 return addr;
2195 }
2196
2197 #if COUNT_OPS
2198 static int opcode_counts[512];
2199
2200 #define COUNT_OP(op) opcode_counts[op]++
2201 #else
2202 #define COUNT_OP(op)
2203 #endif
2204
2205 #if DEBUG_INTERP
2206 #define DUMP_INSTR() \
2207 if (tracing > 1) { \
2208 char *ins; \
2209 if (sp > frame->stack) { \
2210 ins = dump_stack (frame->stack, sp); \
2211 } else { \
2212 ins = g_strdup (""); \
2213 } \
2214 sp->data.l = 0; \
2215 output_indent (); \
2216 char *mn = mono_method_full_name (frame->imethod->method, FALSE); \
2217 char *disasm = mono_interp_dis_mintop(rtm->code, ip); \
2218 g_print ("(%p) %s -> %s\t%d:%s\n", mono_thread_internal_current (), mn, disasm, vt_sp - vtalloc, ins); \
2219 g_free (mn); \
2220 g_free (ins); \
2221 g_free (disasm); \
2222 }
2223 #else
2224 #define DUMP_INSTR()
2225 #endif
2226
2227 #ifdef __GNUC__
2228 #define USE_COMPUTED_GOTO 1
2229 #endif
2230 #if USE_COMPUTED_GOTO
2231 #define MINT_IN_SWITCH(op) COUNT_OP(op); goto *in_labels[op];
2232 #define MINT_IN_CASE(x) LAB_ ## x:
2233 #if DEBUG_INTERP
2234 #define MINT_IN_BREAK if (tracing > 1) goto main_loop; else { COUNT_OP(*ip); goto *in_labels[*ip]; }
2235 #else
2236 #define MINT_IN_BREAK { COUNT_OP(*ip); goto *in_labels[*ip]; }
2237 #endif
2238 #define MINT_IN_DEFAULT mint_default: if (0) goto mint_default; /* make gcc shut up */
2239 #else
2240 #define MINT_IN_SWITCH(op) switch (op)
2241 #define MINT_IN_CASE(x) case x:
2242 #define MINT_IN_BREAK break
2243 #define MINT_IN_DEFAULT default:
2244 #endif
2245
2246 /*
2247 * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index.
2248 * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME.
2249 */
2250 static void
interp_exec_method_full(InterpFrame * frame,ThreadContext * context,guint16 * start_with_ip,MonoException * filter_exception,int exit_at_finally,InterpFrame * base_frame)2251 interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame)
2252 {
2253 InterpFrame child_frame;
2254 GSList *finally_ips = NULL;
2255 const unsigned short *endfinally_ip = NULL;
2256 const unsigned short *ip = NULL;
2257 register stackval *sp;
2258 InterpMethod *rtm;
2259 #if DEBUG_INTERP
2260 gint tracing = global_tracing;
2261 unsigned char *vtalloc;
2262 #else
2263 gint tracing = 0;
2264 #endif
2265 int i32;
2266 unsigned char *vt_sp;
2267 unsigned char *locals;
2268 MonoError error;
2269 MonoObject *o = NULL;
2270 MonoClass *c;
2271 #if USE_COMPUTED_GOTO
2272 static void *in_labels[] = {
2273 #define OPDEF(a,b,c,d) \
2274 &&LAB_ ## a,
2275 #include "mintops.def"
2276 0 };
2277 #endif
2278
2279 frame->ex = NULL;
2280 frame->ex_handler = NULL;
2281 frame->ip = NULL;
2282 frame->domain = mono_domain_get ();
2283 context->current_frame = frame;
2284
2285 debug_enter (frame, &tracing);
2286
2287 if (!frame->imethod->transformed) {
2288 #if DEBUG_INTERP
2289 char *mn = mono_method_full_name (frame->imethod->method, TRUE);
2290 g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
2291 g_free (mn);
2292 #endif
2293
2294 do_transform_method (frame, context);
2295 if (frame->ex) {
2296 context->search_for_handler = 1;
2297 rtm = NULL;
2298 ip = NULL;
2299 goto exit_frame;
2300 }
2301 }
2302
2303 rtm = frame->imethod;
2304 if (!start_with_ip) {
2305 frame->args = alloca (rtm->alloca_size);
2306 memset (frame->args, 0, rtm->alloca_size);
2307
2308 ip = rtm->code;
2309 } else {
2310 ip = start_with_ip;
2311 if (base_frame) {
2312 frame->args = alloca (rtm->alloca_size);
2313 memcpy (frame->args, base_frame->args, rtm->alloca_size);
2314 }
2315 }
2316 sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size);
2317 vt_sp = (unsigned char *) sp + rtm->stack_size;
2318 #if DEBUG_INTERP
2319 vtalloc = vt_sp;
2320 #endif
2321 locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
2322 frame->locals = locals;
2323 child_frame.parent = frame;
2324
2325 if (filter_exception) {
2326 sp->data.p = filter_exception;
2327 sp++;
2328 }
2329
2330 /*
2331 * using while (ip < end) may result in a 15% performance drop,
2332 * but it may be useful for debug
2333 */
2334 while (1) {
2335 main_loop:
2336 /* g_assert (sp >= frame->stack); */
2337 /* g_assert(vt_sp - vtalloc <= rtm->vt_stack_size); */
2338 DUMP_INSTR();
2339 MINT_IN_SWITCH (*ip) {
2340 MINT_IN_CASE(MINT_INITLOCALS)
2341 memset (locals, 0, rtm->locals_size);
2342 ++ip;
2343 MINT_IN_BREAK;
2344 MINT_IN_CASE(MINT_NOP)
2345 ++ip;
2346 MINT_IN_BREAK;
2347 MINT_IN_CASE(MINT_NIY)
2348 g_error ("mint_niy: instruction not implemented yet. This shouldn't happen.");
2349 MINT_IN_BREAK;
2350 MINT_IN_CASE(MINT_BREAK)
2351 ++ip;
2352 do_debugger_tramp (mono_debugger_agent_user_break, frame);
2353 MINT_IN_BREAK;
2354 MINT_IN_CASE(MINT_LDNULL)
2355 sp->data.p = NULL;
2356 ++ip;
2357 ++sp;
2358 MINT_IN_BREAK;
2359 MINT_IN_CASE(MINT_VTRESULT) {
2360 int ret_size = * (guint16 *)(ip + 1);
2361 unsigned char *ret_vt_sp = vt_sp;
2362 vt_sp -= READ32(ip + 2);
2363 if (ret_size > 0) {
2364 memmove (vt_sp, ret_vt_sp, ret_size);
2365 sp [-1].data.p = vt_sp;
2366 vt_sp += (ret_size + 7) & ~7;
2367 }
2368 ip += 4;
2369 MINT_IN_BREAK;
2370 }
2371 #define LDC(n) do { sp->data.i = (n); ++ip; ++sp; } while (0)
2372 MINT_IN_CASE(MINT_LDC_I4_M1)
2373 LDC(-1);
2374 MINT_IN_BREAK;
2375 MINT_IN_CASE(MINT_LDC_I4_0)
2376 LDC(0);
2377 MINT_IN_BREAK;
2378 MINT_IN_CASE(MINT_LDC_I4_1)
2379 LDC(1);
2380 MINT_IN_BREAK;
2381 MINT_IN_CASE(MINT_LDC_I4_2)
2382 LDC(2);
2383 MINT_IN_BREAK;
2384 MINT_IN_CASE(MINT_LDC_I4_3)
2385 LDC(3);
2386 MINT_IN_BREAK;
2387 MINT_IN_CASE(MINT_LDC_I4_4)
2388 LDC(4);
2389 MINT_IN_BREAK;
2390 MINT_IN_CASE(MINT_LDC_I4_5)
2391 LDC(5);
2392 MINT_IN_BREAK;
2393 MINT_IN_CASE(MINT_LDC_I4_6)
2394 LDC(6);
2395 MINT_IN_BREAK;
2396 MINT_IN_CASE(MINT_LDC_I4_7)
2397 LDC(7);
2398 MINT_IN_BREAK;
2399 MINT_IN_CASE(MINT_LDC_I4_8)
2400 LDC(8);
2401 MINT_IN_BREAK;
2402 MINT_IN_CASE(MINT_LDC_I4_S)
2403 sp->data.i = *(const short *)(ip + 1);
2404 ip += 2;
2405 ++sp;
2406 MINT_IN_BREAK;
2407 MINT_IN_CASE(MINT_LDC_I4)
2408 ++ip;
2409 sp->data.i = READ32 (ip);
2410 ip += 2;
2411 ++sp;
2412 MINT_IN_BREAK;
2413 MINT_IN_CASE(MINT_LDC_I8)
2414 ++ip;
2415 sp->data.l = READ64 (ip);
2416 ip += 4;
2417 ++sp;
2418 MINT_IN_BREAK;
2419 MINT_IN_CASE(MINT_LDC_R4) {
2420 guint32 val;
2421 ++ip;
2422 val = READ32(ip);
2423 sp->data.f = * (float *)&val;
2424 ip += 2;
2425 ++sp;
2426 MINT_IN_BREAK;
2427 }
2428 MINT_IN_CASE(MINT_LDC_R8)
2429 sp->data.l = READ64 (ip + 1); /* note union usage */
2430 ip += 5;
2431 ++sp;
2432 MINT_IN_BREAK;
2433 MINT_IN_CASE(MINT_DUP)
2434 sp [0] = sp[-1];
2435 ++sp;
2436 ++ip;
2437 MINT_IN_BREAK;
2438 MINT_IN_CASE(MINT_DUP_VT)
2439 i32 = READ32 (ip + 1);
2440 sp->data.p = vt_sp;
2441 memcpy(sp->data.p, sp [-1].data.p, i32);
2442 vt_sp += (i32 + 7) & ~7;
2443 ++sp;
2444 ip += 3;
2445 MINT_IN_BREAK;
2446 MINT_IN_CASE(MINT_POP) {
2447 guint16 u16 = (* (guint16 *)(ip + 1)) + 1;
2448 if (u16 > 1)
2449 memmove (sp - u16, sp - 1, (u16 - 1) * sizeof (stackval));
2450 sp--;
2451 ip += 2;
2452 MINT_IN_BREAK;
2453 }
2454 MINT_IN_CASE(MINT_JMP) {
2455 InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
2456
2457 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
2458 MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
2459
2460 if (!new_method->transformed) {
2461 frame->ip = ip;
2462 frame->ex = mono_interp_transform_method (new_method, context, NULL);
2463 if (frame->ex)
2464 goto exit_frame;
2465 }
2466 ip += 2;
2467 if (new_method->alloca_size > rtm->alloca_size)
2468 g_error ("MINT_JMP to method which needs more stack space (%d > %d)", new_method->alloca_size, rtm->alloca_size);
2469 rtm = frame->imethod = new_method;
2470 vt_sp = (unsigned char *) sp + rtm->stack_size;
2471 #if DEBUG_INTERP
2472 vtalloc = vt_sp;
2473 #endif
2474 locals = vt_sp + rtm->vt_stack_size;
2475 frame->locals = locals;
2476 ip = rtm->new_body_start; /* bypass storing input args from callers frame */
2477 MINT_IN_BREAK;
2478 }
2479 MINT_IN_CASE(MINT_CALLI) {
2480 MonoMethodSignature *csignature;
2481 stackval *endsp = sp;
2482
2483 frame->ip = ip;
2484
2485 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2486 ip += 2;
2487 --sp;
2488 --endsp;
2489 child_frame.imethod = sp->data.p;
2490
2491 sp->data.p = vt_sp;
2492 child_frame.retval = sp;
2493 /* decrement by the actual number of args */
2494 sp -= csignature->param_count;
2495 if (csignature->hasthis)
2496 --sp;
2497 child_frame.stack_args = sp;
2498
2499 if (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
2500 child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_native_wrapper (child_frame.imethod->method, FALSE, FALSE), &error);
2501 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
2502 }
2503
2504 if (csignature->hasthis) {
2505 MonoObject *this_arg = sp->data.p;
2506
2507 if (this_arg->vtable->klass->valuetype) {
2508 gpointer *unboxed = mono_object_unbox (this_arg);
2509 sp [0].data.p = unboxed;
2510 }
2511 }
2512
2513 interp_exec_method (&child_frame, context);
2514
2515 context->current_frame = frame;
2516
2517 if (context->has_resume_state) {
2518 if (frame == context->handler_frame)
2519 SET_RESUME_STATE (context);
2520 else
2521 goto exit_frame;
2522 }
2523
2524 CHECK_CHILD_EX (child_frame, ip - 2);
2525
2526 /* need to handle typedbyref ... */
2527 if (csignature->ret->type != MONO_TYPE_VOID) {
2528 *sp = *endsp;
2529 sp++;
2530 }
2531 MINT_IN_BREAK;
2532 }
2533 MINT_IN_CASE(MINT_CALLI_NAT) {
2534 MonoMethodSignature *csignature;
2535 stackval *endsp = sp;
2536 unsigned char *code = NULL;
2537
2538 frame->ip = ip;
2539
2540 csignature = rtm->data_items [* (guint16 *)(ip + 1)];
2541 ip += 2;
2542 --sp;
2543 --endsp;
2544 code = sp->data.p;
2545 child_frame.imethod = NULL;
2546
2547 sp->data.p = vt_sp;
2548 child_frame.retval = sp;
2549 /* decrement by the actual number of args */
2550 sp -= csignature->param_count;
2551 if (csignature->hasthis)
2552 --sp;
2553 child_frame.stack_args = sp;
2554 ves_pinvoke_method (&child_frame, csignature, (MonoFuncV) code, FALSE, context);
2555
2556 context->current_frame = frame;
2557
2558 if (context->has_resume_state) {
2559 if (frame == context->handler_frame)
2560 SET_RESUME_STATE (context);
2561 else
2562 goto exit_frame;
2563 }
2564
2565 CHECK_CHILD_EX (child_frame, ip - 2);
2566
2567 /* need to handle typedbyref ... */
2568 if (csignature->ret->type != MONO_TYPE_VOID) {
2569 *sp = *endsp;
2570 sp++;
2571 }
2572 MINT_IN_BREAK;
2573 }
2574 MINT_IN_CASE(MINT_CALL) {
2575 stackval *endsp = sp;
2576
2577 frame->ip = ip;
2578
2579 child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
2580 ip += 2;
2581 sp->data.p = vt_sp;
2582 child_frame.retval = sp;
2583 /* decrement by the actual number of args */
2584 sp -= child_frame.imethod->param_count;
2585 if (child_frame.imethod->hasthis) {
2586 --sp;
2587 MonoObject *this_arg = sp->data.p;
2588 if (!this_arg && (child_frame.imethod->method->flags & METHOD_ATTRIBUTE_VIRTUAL))
2589 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2590 }
2591
2592 child_frame.stack_args = sp;
2593
2594 interp_exec_method (&child_frame, context);
2595
2596 context->current_frame = frame;
2597
2598 if (context->has_resume_state) {
2599 if (frame == context->handler_frame)
2600 SET_RESUME_STATE (context);
2601 else
2602 goto exit_frame;
2603 }
2604 CHECK_CHILD_EX (child_frame, ip - 2);
2605
2606 /* need to handle typedbyref ... */
2607 *sp = *endsp;
2608 sp++;
2609 MINT_IN_BREAK;
2610 }
2611 MINT_IN_CASE(MINT_VCALL) {
2612 frame->ip = ip;
2613
2614 child_frame.imethod = rtm->data_items [* (guint16 *)(ip + 1)];
2615 ip += 2;
2616
2617 sp->data.p = vt_sp;
2618 child_frame.retval = sp;
2619 /* decrement by the actual number of args */
2620 sp -= child_frame.imethod->param_count;
2621 if (child_frame.imethod->hasthis) {
2622 --sp;
2623 MonoObject *this_arg = sp->data.p;
2624 if (!this_arg)
2625 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2626 }
2627 child_frame.stack_args = sp;
2628
2629 interp_exec_method (&child_frame, context);
2630
2631 context->current_frame = frame;
2632
2633 if (context->has_resume_state) {
2634 if (frame == context->handler_frame)
2635 SET_RESUME_STATE (context);
2636 else
2637 goto exit_frame;
2638 }
2639
2640 CHECK_CHILD_EX (child_frame, ip - 2);
2641 MINT_IN_BREAK;
2642 }
2643
2644 MINT_IN_CASE(MINT_JIT_CALL) {
2645 InterpMethod *rmethod = rtm->data_items [* (guint16 *)(ip + 1)];
2646 frame->ip = ip;
2647 ip += 2;
2648 sp = do_jit_call (sp, vt_sp, context, frame, rmethod);
2649
2650 if (context->has_resume_state) {
2651 /*
2652 * If this bit is set, it means the call has thrown the exception, and we
2653 * reached this point because the EH code in mono_handle_exception ()
2654 * unwound all the JITted frames below us. mono_interp_set_resume_state ()
2655 * has set the fields in context to indicate where we have to resume execution.
2656 */
2657 if (frame == context->handler_frame)
2658 SET_RESUME_STATE (context);
2659 else
2660 goto exit_frame;
2661 }
2662 if (rmethod->rtype->type != MONO_TYPE_VOID)
2663 sp++;
2664
2665 MINT_IN_BREAK;
2666 }
2667
2668 MINT_IN_CASE(MINT_CALLVIRT) {
2669 stackval *endsp = sp;
2670 MonoObject *this_arg;
2671 guint32 token;
2672
2673 frame->ip = ip;
2674
2675 token = * (unsigned short *)(ip + 1);
2676 ip += 2;
2677 child_frame.imethod = rtm->data_items [token];
2678 sp->data.p = vt_sp;
2679 child_frame.retval = sp;
2680
2681 /* decrement by the actual number of args */
2682 sp -= child_frame.imethod->param_count + 1;
2683 child_frame.stack_args = sp;
2684 this_arg = sp->data.p;
2685 if (!this_arg)
2686 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2687 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
2688
2689 MonoClass *this_class = this_arg->vtable->klass;
2690 if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
2691 /* unbox */
2692 gpointer *unboxed = mono_object_unbox (this_arg);
2693 sp [0].data.p = unboxed;
2694 }
2695
2696 interp_exec_method (&child_frame, context);
2697
2698 context->current_frame = frame;
2699
2700 if (context->has_resume_state) {
2701 if (frame == context->handler_frame)
2702 SET_RESUME_STATE (context);
2703 else
2704 goto exit_frame;
2705 }
2706
2707 CHECK_CHILD_EX (child_frame, ip - 2);
2708
2709 /* need to handle typedbyref ... */
2710 *sp = *endsp;
2711 sp++;
2712 MINT_IN_BREAK;
2713 }
2714 MINT_IN_CASE(MINT_VCALLVIRT) {
2715 MonoObject *this_arg;
2716 guint32 token;
2717
2718 frame->ip = ip;
2719
2720 token = * (unsigned short *)(ip + 1);
2721 ip += 2;
2722 child_frame.imethod = rtm->data_items [token];
2723 sp->data.p = vt_sp;
2724 child_frame.retval = sp;
2725
2726 /* decrement by the actual number of args */
2727 sp -= child_frame.imethod->param_count + 1;
2728 child_frame.stack_args = sp;
2729 this_arg = sp->data.p;
2730 if (!this_arg)
2731 THROW_EX (mono_get_exception_null_reference(), ip - 2);
2732 child_frame.imethod = get_virtual_method (child_frame.imethod, this_arg);
2733
2734 MonoClass *this_class = this_arg->vtable->klass;
2735 if (this_class->valuetype && child_frame.imethod->method->klass->valuetype) {
2736 gpointer *unboxed = mono_object_unbox (this_arg);
2737 sp [0].data.p = unboxed;
2738 }
2739
2740 interp_exec_method (&child_frame, context);
2741
2742 context->current_frame = frame;
2743
2744 if (context->has_resume_state) {
2745 if (frame == context->handler_frame)
2746 SET_RESUME_STATE (context);
2747 else
2748 goto exit_frame;
2749 }
2750
2751 CHECK_CHILD_EX (child_frame, ip - 2);
2752 MINT_IN_BREAK;
2753 }
2754 MINT_IN_CASE(MINT_CALLRUN)
2755 ves_imethod (frame, context);
2756 if (frame->ex) {
2757 MonoException *fex = frame->ex;
2758 //frame = frame->parent;
2759 THROW_EX (fex, frame->ip);
2760 }
2761 goto exit_frame;
2762 MINT_IN_CASE(MINT_RET)
2763 --sp;
2764 *frame->retval = *sp;
2765 if (sp > frame->stack)
2766 g_warning ("ret: more values on stack: %d", sp-frame->stack);
2767 goto exit_frame;
2768 MINT_IN_CASE(MINT_RET_VOID)
2769 if (sp > frame->stack)
2770 g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->imethod->method, TRUE));
2771 goto exit_frame;
2772 MINT_IN_CASE(MINT_RET_VT)
2773 i32 = READ32(ip + 1);
2774 --sp;
2775 memcpy(frame->retval->data.p, sp->data.p, i32);
2776 if (sp > frame->stack)
2777 g_warning ("ret.vt: more values on stack: %d", sp-frame->stack);
2778 goto exit_frame;
2779 MINT_IN_CASE(MINT_BR_S)
2780 /* Checkpoint to be able to handle aborts */
2781 if (*mono_thread_interruption_request_flag ()) {
2782 MonoException *exc = mono_thread_interruption_checkpoint ();
2783 if (exc)
2784 THROW_EX (exc, ip);
2785 }
2786 ip += (short) *(ip + 1);
2787 MINT_IN_BREAK;
2788 MINT_IN_CASE(MINT_BR)
2789 /* Checkpoint to be able to handle aborts */
2790 if (*mono_thread_interruption_request_flag ()) {
2791 MonoException *exc = mono_thread_interruption_checkpoint ();
2792 if (exc)
2793 THROW_EX (exc, ip);
2794 }
2795 ip += (gint32) READ32(ip + 1);
2796 MINT_IN_BREAK;
2797 #define ZEROP_S(datamem, op) \
2798 --sp; \
2799 if (sp->data.datamem op 0) \
2800 ip += * (gint16 *)(ip + 1); \
2801 else \
2802 ip += 2;
2803
2804 #define ZEROP(datamem, op) \
2805 --sp; \
2806 if (sp->data.datamem op 0) \
2807 ip += READ32(ip + 1); \
2808 else \
2809 ip += 3;
2810
2811 MINT_IN_CASE(MINT_BRFALSE_I4_S)
2812 ZEROP_S(i, ==);
2813 MINT_IN_BREAK;
2814 MINT_IN_CASE(MINT_BRFALSE_I8_S)
2815 ZEROP_S(l, ==);
2816 MINT_IN_BREAK;
2817 MINT_IN_CASE(MINT_BRFALSE_R8_S)
2818 ZEROP_S(f, ==);
2819 MINT_IN_BREAK;
2820 MINT_IN_CASE(MINT_BRFALSE_I4)
2821 ZEROP(i, ==);
2822 MINT_IN_BREAK;
2823 MINT_IN_CASE(MINT_BRFALSE_I8)
2824 ZEROP(l, ==);
2825 MINT_IN_BREAK;
2826 MINT_IN_CASE(MINT_BRFALSE_R8)
2827 ZEROP_S(f, ==);
2828 MINT_IN_BREAK;
2829 MINT_IN_CASE(MINT_BRTRUE_I4_S)
2830 ZEROP_S(i, !=);
2831 MINT_IN_BREAK;
2832 MINT_IN_CASE(MINT_BRTRUE_I8_S)
2833 ZEROP_S(l, !=);
2834 MINT_IN_BREAK;
2835 MINT_IN_CASE(MINT_BRTRUE_R8_S)
2836 ZEROP_S(f, !=);
2837 MINT_IN_BREAK;
2838 MINT_IN_CASE(MINT_BRTRUE_I4)
2839 ZEROP(i, !=);
2840 MINT_IN_BREAK;
2841 MINT_IN_CASE(MINT_BRTRUE_I8)
2842 ZEROP(l, !=);
2843 MINT_IN_BREAK;
2844 MINT_IN_CASE(MINT_BRTRUE_R8)
2845 ZEROP(f, !=);
2846 MINT_IN_BREAK;
2847 #define CONDBR_S(cond) \
2848 sp -= 2; \
2849 if (cond) \
2850 ip += * (gint16 *)(ip + 1); \
2851 else \
2852 ip += 2;
2853 #define BRELOP_S(datamem, op) \
2854 CONDBR_S(sp[0].data.datamem op sp[1].data.datamem)
2855
2856 #define CONDBR(cond) \
2857 sp -= 2; \
2858 if (cond) \
2859 ip += READ32(ip + 1); \
2860 else \
2861 ip += 3;
2862
2863 #define BRELOP(datamem, op) \
2864 CONDBR(sp[0].data.datamem op sp[1].data.datamem)
2865
2866 MINT_IN_CASE(MINT_BEQ_I4_S)
2867 BRELOP_S(i, ==)
2868 MINT_IN_BREAK;
2869 MINT_IN_CASE(MINT_BEQ_I8_S)
2870 BRELOP_S(l, ==)
2871 MINT_IN_BREAK;
2872 MINT_IN_CASE(MINT_BEQ_R8_S)
2873 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2874 MINT_IN_BREAK;
2875 MINT_IN_CASE(MINT_BEQ_I4)
2876 BRELOP(i, ==)
2877 MINT_IN_BREAK;
2878 MINT_IN_CASE(MINT_BEQ_I8)
2879 BRELOP(l, ==)
2880 MINT_IN_BREAK;
2881 MINT_IN_CASE(MINT_BEQ_R8)
2882 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f == sp[1].data.f)
2883 MINT_IN_BREAK;
2884 MINT_IN_CASE(MINT_BGE_I4_S)
2885 BRELOP_S(i, >=)
2886 MINT_IN_BREAK;
2887 MINT_IN_CASE(MINT_BGE_I8_S)
2888 BRELOP_S(l, >=)
2889 MINT_IN_BREAK;
2890 MINT_IN_CASE(MINT_BGE_R8_S)
2891 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2892 MINT_IN_BREAK;
2893 MINT_IN_CASE(MINT_BGE_I4)
2894 BRELOP(i, >=)
2895 MINT_IN_BREAK;
2896 MINT_IN_CASE(MINT_BGE_I8)
2897 BRELOP(l, >=)
2898 MINT_IN_BREAK;
2899 MINT_IN_CASE(MINT_BGE_R8)
2900 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f >= sp[1].data.f)
2901 MINT_IN_BREAK;
2902 MINT_IN_CASE(MINT_BGT_I4_S)
2903 BRELOP_S(i, >)
2904 MINT_IN_BREAK;
2905 MINT_IN_CASE(MINT_BGT_I8_S)
2906 BRELOP_S(l, >)
2907 MINT_IN_BREAK;
2908 MINT_IN_CASE(MINT_BGT_R8_S)
2909 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2910 MINT_IN_BREAK;
2911 MINT_IN_CASE(MINT_BGT_I4)
2912 BRELOP(i, >)
2913 MINT_IN_BREAK;
2914 MINT_IN_CASE(MINT_BGT_I8)
2915 BRELOP(l, >)
2916 MINT_IN_BREAK;
2917 MINT_IN_CASE(MINT_BGT_R8)
2918 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f > sp[1].data.f)
2919 MINT_IN_BREAK;
2920 MINT_IN_CASE(MINT_BLT_I4_S)
2921 BRELOP_S(i, <)
2922 MINT_IN_BREAK;
2923 MINT_IN_CASE(MINT_BLT_I8_S)
2924 BRELOP_S(l, <)
2925 MINT_IN_BREAK;
2926 MINT_IN_CASE(MINT_BLT_R8_S)
2927 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2928 MINT_IN_BREAK;
2929 MINT_IN_CASE(MINT_BLT_I4)
2930 BRELOP(i, <)
2931 MINT_IN_BREAK;
2932 MINT_IN_CASE(MINT_BLT_I8)
2933 BRELOP(l, <)
2934 MINT_IN_BREAK;
2935 MINT_IN_CASE(MINT_BLT_R8)
2936 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f < sp[1].data.f)
2937 MINT_IN_BREAK;
2938 MINT_IN_CASE(MINT_BLE_I4_S)
2939 BRELOP_S(i, <=)
2940 MINT_IN_BREAK;
2941 MINT_IN_CASE(MINT_BLE_I8_S)
2942 BRELOP_S(l, <=)
2943 MINT_IN_BREAK;
2944 MINT_IN_CASE(MINT_BLE_R8_S)
2945 CONDBR_S(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2946 MINT_IN_BREAK;
2947 MINT_IN_CASE(MINT_BLE_I4)
2948 BRELOP(i, <=)
2949 MINT_IN_BREAK;
2950 MINT_IN_CASE(MINT_BLE_I8)
2951 BRELOP(l, <=)
2952 MINT_IN_BREAK;
2953 MINT_IN_CASE(MINT_BLE_R8)
2954 CONDBR(!isunordered (sp [0].data.f, sp [1].data.f) && sp[0].data.f <= sp[1].data.f)
2955 MINT_IN_BREAK;
2956 MINT_IN_CASE(MINT_BNE_UN_I4_S)
2957 BRELOP_S(i, !=)
2958 MINT_IN_BREAK;
2959 MINT_IN_CASE(MINT_BNE_UN_I8_S)
2960 BRELOP_S(l, !=)
2961 MINT_IN_BREAK;
2962 MINT_IN_CASE(MINT_BNE_UN_R8_S)
2963 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2964 MINT_IN_BREAK;
2965 MINT_IN_CASE(MINT_BNE_UN_I4)
2966 BRELOP(i, !=)
2967 MINT_IN_BREAK;
2968 MINT_IN_CASE(MINT_BNE_UN_I8)
2969 BRELOP(l, !=)
2970 MINT_IN_BREAK;
2971 MINT_IN_CASE(MINT_BNE_UN_R8)
2972 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f != sp[1].data.f)
2973 MINT_IN_BREAK;
2974
2975 #define BRELOP_S_CAST(datamem, op, type) \
2976 sp -= 2; \
2977 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2978 ip += * (gint16 *)(ip + 1); \
2979 else \
2980 ip += 2;
2981
2982 #define BRELOP_CAST(datamem, op, type) \
2983 sp -= 2; \
2984 if ((type) sp[0].data.datamem op (type) sp[1].data.datamem) \
2985 ip += READ32(ip + 1); \
2986 else \
2987 ip += 3;
2988
2989 MINT_IN_CASE(MINT_BGE_UN_I4_S)
2990 BRELOP_S_CAST(i, >=, guint32);
2991 MINT_IN_BREAK;
2992 MINT_IN_CASE(MINT_BGE_UN_I8_S)
2993 BRELOP_S_CAST(l, >=, guint64);
2994 MINT_IN_BREAK;
2995 MINT_IN_CASE(MINT_BGE_UN_R8_S)
2996 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
2997 MINT_IN_BREAK;
2998 MINT_IN_CASE(MINT_BGE_UN_I4)
2999 BRELOP_CAST(i, >=, guint32);
3000 MINT_IN_BREAK;
3001 MINT_IN_CASE(MINT_BGE_UN_I8)
3002 BRELOP_CAST(l, >=, guint64);
3003 MINT_IN_BREAK;
3004 MINT_IN_CASE(MINT_BGE_UN_R8)
3005 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f >= sp[1].data.f)
3006 MINT_IN_BREAK;
3007 MINT_IN_CASE(MINT_BGT_UN_I4_S)
3008 BRELOP_S_CAST(i, >, guint32);
3009 MINT_IN_BREAK;
3010 MINT_IN_CASE(MINT_BGT_UN_I8_S)
3011 BRELOP_S_CAST(l, >, guint64);
3012 MINT_IN_BREAK;
3013 MINT_IN_CASE(MINT_BGT_UN_R8_S)
3014 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3015 MINT_IN_BREAK;
3016 MINT_IN_CASE(MINT_BGT_UN_I4)
3017 BRELOP_CAST(i, >, guint32);
3018 MINT_IN_BREAK;
3019 MINT_IN_CASE(MINT_BGT_UN_I8)
3020 BRELOP_CAST(l, >, guint64);
3021 MINT_IN_BREAK;
3022 MINT_IN_CASE(MINT_BGT_UN_R8)
3023 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f > sp[1].data.f)
3024 MINT_IN_BREAK;
3025 MINT_IN_CASE(MINT_BLE_UN_I4_S)
3026 BRELOP_S_CAST(i, <=, guint32);
3027 MINT_IN_BREAK;
3028 MINT_IN_CASE(MINT_BLE_UN_I8_S)
3029 BRELOP_S_CAST(l, <=, guint64);
3030 MINT_IN_BREAK;
3031 MINT_IN_CASE(MINT_BLE_UN_R8_S)
3032 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3033 MINT_IN_BREAK;
3034 MINT_IN_CASE(MINT_BLE_UN_I4)
3035 BRELOP_CAST(i, <=, guint32);
3036 MINT_IN_BREAK;
3037 MINT_IN_CASE(MINT_BLE_UN_I8)
3038 BRELOP_CAST(l, <=, guint64);
3039 MINT_IN_BREAK;
3040 MINT_IN_CASE(MINT_BLE_UN_R8)
3041 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f <= sp[1].data.f)
3042 MINT_IN_BREAK;
3043 MINT_IN_CASE(MINT_BLT_UN_I4_S)
3044 BRELOP_S_CAST(i, <, guint32);
3045 MINT_IN_BREAK;
3046 MINT_IN_CASE(MINT_BLT_UN_I8_S)
3047 BRELOP_S_CAST(l, <, guint64);
3048 MINT_IN_BREAK;
3049 MINT_IN_CASE(MINT_BLT_UN_R8_S)
3050 CONDBR_S(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3051 MINT_IN_BREAK;
3052 MINT_IN_CASE(MINT_BLT_UN_I4)
3053 BRELOP_CAST(i, <, guint32);
3054 MINT_IN_BREAK;
3055 MINT_IN_CASE(MINT_BLT_UN_I8)
3056 BRELOP_CAST(l, <, guint64);
3057 MINT_IN_BREAK;
3058 MINT_IN_CASE(MINT_BLT_UN_R8)
3059 CONDBR(isunordered (sp [0].data.f, sp [1].data.f) || sp[0].data.f < sp[1].data.f)
3060 MINT_IN_BREAK;
3061 MINT_IN_CASE(MINT_SWITCH) {
3062 guint32 n;
3063 const unsigned short *st;
3064 ++ip;
3065 n = READ32 (ip);
3066 ip += 2;
3067 st = ip + 2 * n;
3068 --sp;
3069 if ((guint32)sp->data.i < n) {
3070 gint offset;
3071 ip += 2 * (guint32)sp->data.i;
3072 offset = READ32 (ip);
3073 ip = ip + offset;
3074 } else {
3075 ip = st;
3076 }
3077 MINT_IN_BREAK;
3078 }
3079 MINT_IN_CASE(MINT_LDIND_I1)
3080 ++ip;
3081 sp[-1].data.i = *(gint8*)sp[-1].data.p;
3082 MINT_IN_BREAK;
3083 MINT_IN_CASE(MINT_LDIND_U1)
3084 ++ip;
3085 sp[-1].data.i = *(guint8*)sp[-1].data.p;
3086 MINT_IN_BREAK;
3087 MINT_IN_CASE(MINT_LDIND_I2)
3088 ++ip;
3089 sp[-1].data.i = *(gint16*)sp[-1].data.p;
3090 MINT_IN_BREAK;
3091 MINT_IN_CASE(MINT_LDIND_U2)
3092 ++ip;
3093 sp[-1].data.i = *(guint16*)sp[-1].data.p;
3094 MINT_IN_BREAK;
3095 MINT_IN_CASE(MINT_LDIND_I4) /* Fall through */
3096 MINT_IN_CASE(MINT_LDIND_U4)
3097 ++ip;
3098 sp[-1].data.i = *(gint32*)sp[-1].data.p;
3099 MINT_IN_BREAK;
3100 MINT_IN_CASE(MINT_LDIND_I8)
3101 ++ip;
3102 /* memmove handles unaligned case */
3103 memmove (&sp [-1].data.l, sp [-1].data.p, sizeof (gint64));
3104 MINT_IN_BREAK;
3105 MINT_IN_CASE(MINT_LDIND_I) {
3106 guint16 offset = * (guint16 *)(ip + 1);
3107 sp[-1 - offset].data.p = *(gpointer*)sp[-1 - offset].data.p;
3108 ip += 2;
3109 MINT_IN_BREAK;
3110 }
3111 MINT_IN_CASE(MINT_LDIND_R4)
3112 ++ip;
3113 sp[-1].data.f = *(gfloat*)sp[-1].data.p;
3114 MINT_IN_BREAK;
3115 MINT_IN_CASE(MINT_LDIND_R8)
3116 ++ip;
3117 sp[-1].data.f = *(gdouble*)sp[-1].data.p;
3118 MINT_IN_BREAK;
3119 MINT_IN_CASE(MINT_LDIND_REF)
3120 ++ip;
3121 sp[-1].data.p = *(gpointer*)sp[-1].data.p;
3122 MINT_IN_BREAK;
3123 MINT_IN_CASE(MINT_STIND_REF)
3124 ++ip;
3125 sp -= 2;
3126 mono_gc_wbarrier_generic_store (sp->data.p, sp [1].data.p);
3127 MINT_IN_BREAK;
3128 MINT_IN_CASE(MINT_STIND_I1)
3129 ++ip;
3130 sp -= 2;
3131 * (gint8 *) sp->data.p = (gint8)sp[1].data.i;
3132 MINT_IN_BREAK;
3133 MINT_IN_CASE(MINT_STIND_I2)
3134 ++ip;
3135 sp -= 2;
3136 * (gint16 *) sp->data.p = (gint16)sp[1].data.i;
3137 MINT_IN_BREAK;
3138 MINT_IN_CASE(MINT_STIND_I4)
3139 ++ip;
3140 sp -= 2;
3141 * (gint32 *) sp->data.p = sp[1].data.i;
3142 MINT_IN_BREAK;
3143 MINT_IN_CASE(MINT_STIND_I)
3144 ++ip;
3145 sp -= 2;
3146 * (mono_i *) sp->data.p = (mono_i)sp[1].data.p;
3147 MINT_IN_BREAK;
3148 MINT_IN_CASE(MINT_STIND_I8)
3149 ++ip;
3150 sp -= 2;
3151 * (gint64 *) sp->data.p = sp[1].data.l;
3152 MINT_IN_BREAK;
3153 MINT_IN_CASE(MINT_STIND_R4)
3154 ++ip;
3155 sp -= 2;
3156 * (float *) sp->data.p = (gfloat)sp[1].data.f;
3157 MINT_IN_BREAK;
3158 MINT_IN_CASE(MINT_STIND_R8)
3159 ++ip;
3160 sp -= 2;
3161 * (double *) sp->data.p = sp[1].data.f;
3162 MINT_IN_BREAK;
3163 MINT_IN_CASE(MINT_MONO_ATOMIC_STORE_I4)
3164 ++ip;
3165 sp -= 2;
3166 mono_atomic_store_i32 ((gint32 *) sp->data.p, sp [1].data.i);
3167 MINT_IN_BREAK;
3168 #define BINOP(datamem, op) \
3169 --sp; \
3170 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.datamem; \
3171 ++ip;
3172 MINT_IN_CASE(MINT_ADD_I4)
3173 BINOP(i, +);
3174 MINT_IN_BREAK;
3175 MINT_IN_CASE(MINT_ADD_I8)
3176 BINOP(l, +);
3177 MINT_IN_BREAK;
3178 MINT_IN_CASE(MINT_ADD_R8)
3179 BINOP(f, +);
3180 MINT_IN_BREAK;
3181 MINT_IN_CASE(MINT_ADD1_I4)
3182 ++sp [-1].data.i;
3183 ++ip;
3184 MINT_IN_BREAK;
3185 MINT_IN_CASE(MINT_SUB_I4)
3186 BINOP(i, -);
3187 MINT_IN_BREAK;
3188 MINT_IN_CASE(MINT_SUB_I8)
3189 BINOP(l, -);
3190 MINT_IN_BREAK;
3191 MINT_IN_CASE(MINT_SUB_R8)
3192 BINOP(f, -);
3193 MINT_IN_BREAK;
3194 MINT_IN_CASE(MINT_SUB1_I4)
3195 --sp [-1].data.i;
3196 ++ip;
3197 MINT_IN_BREAK;
3198 MINT_IN_CASE(MINT_MUL_I4)
3199 BINOP(i, *);
3200 MINT_IN_BREAK;
3201 MINT_IN_CASE(MINT_MUL_I8)
3202 BINOP(l, *);
3203 MINT_IN_BREAK;
3204 MINT_IN_CASE(MINT_MUL_R8)
3205 BINOP(f, *);
3206 MINT_IN_BREAK;
3207 MINT_IN_CASE(MINT_DIV_I4)
3208 if (sp [-1].data.i == 0)
3209 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3210 if (sp [-1].data.i == (-1))
3211 THROW_EX (mono_get_exception_overflow (), ip);
3212 BINOP(i, /);
3213 MINT_IN_BREAK;
3214 MINT_IN_CASE(MINT_DIV_I8)
3215 if (sp [-1].data.l == 0)
3216 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3217 if (sp [-1].data.l == (-1))
3218 THROW_EX (mono_get_exception_overflow (), ip);
3219 BINOP(l, /);
3220 MINT_IN_BREAK;
3221 MINT_IN_CASE(MINT_DIV_R8)
3222 BINOP(f, /);
3223 MINT_IN_BREAK;
3224
3225 #define BINOP_CAST(datamem, op, type) \
3226 --sp; \
3227 sp [-1].data.datamem = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
3228 ++ip;
3229 MINT_IN_CASE(MINT_DIV_UN_I4)
3230 if (sp [-1].data.i == 0)
3231 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3232 BINOP_CAST(i, /, guint32);
3233 MINT_IN_BREAK;
3234 MINT_IN_CASE(MINT_DIV_UN_I8)
3235 if (sp [-1].data.l == 0)
3236 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3237 BINOP_CAST(l, /, guint64);
3238 MINT_IN_BREAK;
3239 MINT_IN_CASE(MINT_REM_I4)
3240 if (sp [-1].data.i == 0)
3241 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3242 if (sp [-1].data.i == (-1))
3243 THROW_EX (mono_get_exception_overflow (), ip);
3244 BINOP(i, %);
3245 MINT_IN_BREAK;
3246 MINT_IN_CASE(MINT_REM_I8)
3247 if (sp [-1].data.l == 0)
3248 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3249 if (sp [-1].data.l == (-1))
3250 THROW_EX (mono_get_exception_overflow (), ip);
3251 BINOP(l, %);
3252 MINT_IN_BREAK;
3253 MINT_IN_CASE(MINT_REM_R8)
3254 /* FIXME: what do we actually do here? */
3255 --sp;
3256 sp [-1].data.f = fmod (sp [-1].data.f, sp [0].data.f);
3257 ++ip;
3258 MINT_IN_BREAK;
3259 MINT_IN_CASE(MINT_REM_UN_I4)
3260 if (sp [-1].data.i == 0)
3261 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3262 BINOP_CAST(i, %, guint32);
3263 MINT_IN_BREAK;
3264 MINT_IN_CASE(MINT_REM_UN_I8)
3265 if (sp [-1].data.l == 0)
3266 THROW_EX (mono_get_exception_divide_by_zero (), ip);
3267 BINOP_CAST(l, %, guint64);
3268 MINT_IN_BREAK;
3269 MINT_IN_CASE(MINT_AND_I4)
3270 BINOP(i, &);
3271 MINT_IN_BREAK;
3272 MINT_IN_CASE(MINT_AND_I8)
3273 BINOP(l, &);
3274 MINT_IN_BREAK;
3275 MINT_IN_CASE(MINT_OR_I4)
3276 BINOP(i, |);
3277 MINT_IN_BREAK;
3278 MINT_IN_CASE(MINT_OR_I8)
3279 BINOP(l, |);
3280 MINT_IN_BREAK;
3281 MINT_IN_CASE(MINT_XOR_I4)
3282 BINOP(i, ^);
3283 MINT_IN_BREAK;
3284 MINT_IN_CASE(MINT_XOR_I8)
3285 BINOP(l, ^);
3286 MINT_IN_BREAK;
3287
3288 #define SHIFTOP(datamem, op) \
3289 --sp; \
3290 sp [-1].data.datamem = sp [-1].data.datamem op sp [0].data.i; \
3291 ++ip;
3292
3293 MINT_IN_CASE(MINT_SHL_I4)
3294 SHIFTOP(i, <<);
3295 MINT_IN_BREAK;
3296 MINT_IN_CASE(MINT_SHL_I8)
3297 SHIFTOP(l, <<);
3298 MINT_IN_BREAK;
3299 MINT_IN_CASE(MINT_SHR_I4)
3300 SHIFTOP(i, >>);
3301 MINT_IN_BREAK;
3302 MINT_IN_CASE(MINT_SHR_I8)
3303 SHIFTOP(l, >>);
3304 MINT_IN_BREAK;
3305 MINT_IN_CASE(MINT_SHR_UN_I4)
3306 --sp;
3307 sp [-1].data.i = (guint32)sp [-1].data.i >> sp [0].data.i;
3308 ++ip;
3309 MINT_IN_BREAK;
3310 MINT_IN_CASE(MINT_SHR_UN_I8)
3311 --sp;
3312 sp [-1].data.l = (guint64)sp [-1].data.l >> sp [0].data.i;
3313 ++ip;
3314 MINT_IN_BREAK;
3315 MINT_IN_CASE(MINT_NEG_I4)
3316 sp [-1].data.i = - sp [-1].data.i;
3317 ++ip;
3318 MINT_IN_BREAK;
3319 MINT_IN_CASE(MINT_NEG_I8)
3320 sp [-1].data.l = - sp [-1].data.l;
3321 ++ip;
3322 MINT_IN_BREAK;
3323 MINT_IN_CASE(MINT_NEG_R8)
3324 sp [-1].data.f = - sp [-1].data.f;
3325 ++ip;
3326 MINT_IN_BREAK;
3327 MINT_IN_CASE(MINT_NOT_I4)
3328 sp [-1].data.i = ~ sp [-1].data.i;
3329 ++ip;
3330 MINT_IN_BREAK;
3331 MINT_IN_CASE(MINT_NOT_I8)
3332 sp [-1].data.l = ~ sp [-1].data.l;
3333 ++ip;
3334 MINT_IN_BREAK;
3335 MINT_IN_CASE(MINT_CONV_I1_I4)
3336 sp [-1].data.i = (gint8)sp [-1].data.i;
3337 ++ip;
3338 MINT_IN_BREAK;
3339 MINT_IN_CASE(MINT_CONV_I1_I8)
3340 sp [-1].data.i = (gint8)sp [-1].data.l;
3341 ++ip;
3342 MINT_IN_BREAK;
3343 MINT_IN_CASE(MINT_CONV_I1_R8)
3344 sp [-1].data.i = (gint8)sp [-1].data.f;
3345 ++ip;
3346 MINT_IN_BREAK;
3347 MINT_IN_CASE(MINT_CONV_U1_I4)
3348 sp [-1].data.i = (guint8)sp [-1].data.i;
3349 ++ip;
3350 MINT_IN_BREAK;
3351 MINT_IN_CASE(MINT_CONV_U1_I8)
3352 sp [-1].data.i = (guint8)sp [-1].data.l;
3353 ++ip;
3354 MINT_IN_BREAK;
3355 MINT_IN_CASE(MINT_CONV_U1_R8)
3356 sp [-1].data.i = (guint8)sp [-1].data.f;
3357 ++ip;
3358 MINT_IN_BREAK;
3359 MINT_IN_CASE(MINT_CONV_I2_I4)
3360 sp [-1].data.i = (gint16)sp [-1].data.i;
3361 ++ip;
3362 MINT_IN_BREAK;
3363 MINT_IN_CASE(MINT_CONV_I2_I8)
3364 sp [-1].data.i = (gint16)sp [-1].data.l;
3365 ++ip;
3366 MINT_IN_BREAK;
3367 MINT_IN_CASE(MINT_CONV_I2_R8)
3368 sp [-1].data.i = (gint16)sp [-1].data.f;
3369 ++ip;
3370 MINT_IN_BREAK;
3371 MINT_IN_CASE(MINT_CONV_U2_I4)
3372 sp [-1].data.i = (guint16)sp [-1].data.i;
3373 ++ip;
3374 MINT_IN_BREAK;
3375 MINT_IN_CASE(MINT_CONV_U2_I8)
3376 sp [-1].data.i = (guint16)sp [-1].data.l;
3377 ++ip;
3378 MINT_IN_BREAK;
3379 MINT_IN_CASE(MINT_CONV_U2_R8)
3380 sp [-1].data.i = (guint16)sp [-1].data.f;
3381 ++ip;
3382 MINT_IN_BREAK;
3383 MINT_IN_CASE(MINT_CONV_I4_R8)
3384 sp [-1].data.i = (gint32)sp [-1].data.f;
3385 ++ip;
3386 MINT_IN_BREAK;
3387 MINT_IN_CASE(MINT_CONV_U4_I8)
3388 MINT_IN_CASE(MINT_CONV_I4_I8)
3389 sp [-1].data.i = (gint32)sp [-1].data.l;
3390 ++ip;
3391 MINT_IN_BREAK;
3392 MINT_IN_CASE(MINT_CONV_I4_I8_SP)
3393 sp [-2].data.i = (gint32)sp [-2].data.l;
3394 ++ip;
3395 MINT_IN_BREAK;
3396 MINT_IN_CASE(MINT_CONV_U4_R8)
3397 /* needed on arm64 */
3398 if (isinf (sp [-1].data.f))
3399 sp [-1].data.i = 0;
3400 /* needed by wasm */
3401 else if (isnan (sp [-1].data.f))
3402 sp [-1].data.i = 0;
3403 else
3404 sp [-1].data.i = (guint32)sp [-1].data.f;
3405 ++ip;
3406 MINT_IN_BREAK;
3407 MINT_IN_CASE(MINT_CONV_I8_I4)
3408 sp [-1].data.l = sp [-1].data.i;
3409 ++ip;
3410 MINT_IN_BREAK;
3411 MINT_IN_CASE(MINT_CONV_I8_I4_SP)
3412 sp [-2].data.l = sp [-2].data.i;
3413 ++ip;
3414 MINT_IN_BREAK;
3415 MINT_IN_CASE(MINT_CONV_I8_U4)
3416 sp [-1].data.l = (guint32)sp [-1].data.i;
3417 ++ip;
3418 MINT_IN_BREAK;
3419 MINT_IN_CASE(MINT_CONV_I8_R8)
3420 sp [-1].data.l = (gint64)sp [-1].data.f;
3421 ++ip;
3422 MINT_IN_BREAK;
3423 MINT_IN_CASE(MINT_CONV_R4_I4)
3424 sp [-1].data.f = (float)sp [-1].data.i;
3425 ++ip;
3426 MINT_IN_BREAK;
3427 MINT_IN_CASE(MINT_CONV_R4_I8)
3428 sp [-1].data.f = (float)sp [-1].data.l;
3429 ++ip;
3430 MINT_IN_BREAK;
3431 MINT_IN_CASE(MINT_CONV_R4_R8)
3432 sp [-1].data.f = (float)sp [-1].data.f;
3433 ++ip;
3434 MINT_IN_BREAK;
3435 MINT_IN_CASE(MINT_CONV_R8_I4)
3436 sp [-1].data.f = (double)sp [-1].data.i;
3437 ++ip;
3438 MINT_IN_BREAK;
3439 MINT_IN_CASE(MINT_CONV_R8_I8)
3440 sp [-1].data.f = (double)sp [-1].data.l;
3441 ++ip;
3442 MINT_IN_BREAK;
3443 MINT_IN_CASE(MINT_CONV_U8_I4)
3444 sp [-1].data.l = sp [-1].data.i & 0xffffffff;
3445 ++ip;
3446 MINT_IN_BREAK;
3447 MINT_IN_CASE(MINT_CONV_U8_R8)
3448 sp [-1].data.l = (guint64)sp [-1].data.f;
3449 ++ip;
3450 MINT_IN_BREAK;
3451 MINT_IN_CASE(MINT_CPOBJ) {
3452 c = rtm->data_items[* (guint16 *)(ip + 1)];
3453 g_assert (c->valuetype);
3454 /* if this assertion fails, we need to add a write barrier */
3455 g_assert (!MONO_TYPE_IS_REFERENCE (&c->byval_arg));
3456 if (mint_type (&c->byval_arg) == MINT_TYPE_VT)
3457 stackval_from_data (&c->byval_arg, &sp [-2], sp [-1].data.p, FALSE);
3458 else
3459 stackval_from_data (&c->byval_arg, sp [-2].data.p, sp [-1].data.p, FALSE);
3460 ip += 2;
3461 sp -= 2;
3462 MINT_IN_BREAK;
3463 }
3464 MINT_IN_CASE(MINT_LDOBJ) {
3465 void *p;
3466 c = rtm->data_items[* (guint16 *)(ip + 1)];
3467 ip += 2;
3468 p = sp [-1].data.p;
3469 if (mint_type (&c->byval_arg) == MINT_TYPE_VT && !c->enumtype) {
3470 int size = mono_class_value_size (c, NULL);
3471 sp [-1].data.p = vt_sp;
3472 vt_sp += (size + 7) & ~7;
3473 }
3474 stackval_from_data (&c->byval_arg, &sp [-1], p, FALSE);
3475 MINT_IN_BREAK;
3476 }
3477 MINT_IN_CASE(MINT_LDSTR)
3478 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
3479 ++sp;
3480 ip += 2;
3481 MINT_IN_BREAK;
3482 MINT_IN_CASE(MINT_NEWOBJ) {
3483 MonoClass *newobj_class;
3484 MonoMethodSignature *csig;
3485 stackval valuetype_this;
3486 guint32 token;
3487 stackval retval;
3488
3489 frame->ip = ip;
3490
3491 token = * (guint16 *)(ip + 1);
3492 ip += 2;
3493
3494 child_frame.ip = NULL;
3495 child_frame.ex = NULL;
3496
3497 child_frame.imethod = rtm->data_items [token];
3498 csig = mono_method_signature (child_frame.imethod->method);
3499 newobj_class = child_frame.imethod->method->klass;
3500 /*if (profiling_classes) {
3501 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, newobj_class));
3502 count++;
3503 g_hash_table_insert (profiling_classes, newobj_class, GUINT_TO_POINTER (count));
3504 }*/
3505
3506 if (newobj_class->parent == mono_defaults.array_class) {
3507 sp -= csig->param_count;
3508 child_frame.stack_args = sp;
3509 o = ves_array_create (&child_frame, rtm->domain, newobj_class, csig, sp);
3510 CHECK_CHILD_EX (child_frame, ip - 2);
3511 goto array_constructed;
3512 }
3513
3514 g_assert (csig->hasthis);
3515 if (csig->param_count) {
3516 sp -= csig->param_count;
3517 memmove (sp + 1, sp, csig->param_count * sizeof (stackval));
3518 }
3519 child_frame.stack_args = sp;
3520
3521 /*
3522 * First arg is the object.
3523 */
3524 if (newobj_class->valuetype) {
3525 MonoType *t = &newobj_class->byval_arg;
3526 memset (&valuetype_this, 0, sizeof (stackval));
3527 if (!newobj_class->enumtype && (t->type == MONO_TYPE_VALUETYPE || (t->type == MONO_TYPE_GENERICINST && mono_type_generic_inst_is_valuetype (t)))) {
3528 sp->data.p = vt_sp;
3529 valuetype_this.data.p = vt_sp;
3530 } else {
3531 sp->data.p = &valuetype_this;
3532 }
3533 } else {
3534 if (newobj_class != mono_defaults.string_class) {
3535 o = mono_object_new_checked (rtm->domain, newobj_class, &error);
3536 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3537 if (*mono_thread_interruption_request_flag ()) {
3538 MonoException *exc = mono_thread_interruption_checkpoint ();
3539 if (exc) {
3540 frame->ex = exc;
3541 context->search_for_handler = 1;
3542 }
3543 }
3544 sp->data.p = o;
3545 #ifndef DISABLE_REMOTING
3546 if (mono_object_is_transparent_proxy (o)) {
3547 child_frame.imethod = mono_interp_get_imethod (rtm->domain, mono_marshal_get_remoting_invoke_with_check (child_frame.imethod->method), &error);
3548 mono_error_assert_ok (&error);
3549 }
3550 #endif
3551 } else {
3552 sp->data.p = NULL;
3553 child_frame.retval = &retval;
3554 }
3555 }
3556
3557 g_assert (csig->call_convention == MONO_CALL_DEFAULT);
3558
3559 interp_exec_method (&child_frame, context);
3560
3561 context->current_frame = frame;
3562
3563 if (context->has_resume_state) {
3564 if (frame == context->handler_frame)
3565 SET_RESUME_STATE (context);
3566 else
3567 goto exit_frame;
3568 }
3569
3570 CHECK_CHILD_EX (child_frame, ip - 2);
3571 /*
3572 * a constructor returns void, but we need to return the object we created
3573 */
3574 array_constructed:
3575 if (newobj_class->valuetype && !newobj_class->enumtype) {
3576 *sp = valuetype_this;
3577 } else if (newobj_class == mono_defaults.string_class) {
3578 *sp = retval;
3579 } else {
3580 sp->data.p = o;
3581 }
3582 ++sp;
3583 MINT_IN_BREAK;
3584 }
3585 MINT_IN_CASE(MINT_NEWOBJ_MAGIC) {
3586 guint32 token;
3587
3588 frame->ip = ip;
3589 token = * (guint16 *)(ip + 1);
3590 ip += 2;
3591
3592 MINT_IN_BREAK;
3593 }
3594 MINT_IN_CASE(MINT_CASTCLASS)
3595 c = rtm->data_items [*(guint16 *)(ip + 1)];
3596 if ((o = sp [-1].data.p)) {
3597 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3598 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3599 if (!isinst_obj)
3600 THROW_EX (mono_get_exception_invalid_cast (), ip);
3601 }
3602 ip += 2;
3603 MINT_IN_BREAK;
3604 MINT_IN_CASE(MINT_ISINST)
3605 c = rtm->data_items [*(guint16 *)(ip + 1)];
3606 if ((o = sp [-1].data.p)) {
3607 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3608 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3609 if (!isinst_obj)
3610 sp [-1].data.p = NULL;
3611 }
3612 ip += 2;
3613 MINT_IN_BREAK;
3614 MINT_IN_CASE(MINT_CONV_R_UN_I4)
3615 sp [-1].data.f = (double)(guint32)sp [-1].data.i;
3616 ++ip;
3617 MINT_IN_BREAK;
3618 MINT_IN_CASE(MINT_CONV_R_UN_I8)
3619 sp [-1].data.f = (double)(guint64)sp [-1].data.l;
3620 ++ip;
3621 MINT_IN_BREAK;
3622 MINT_IN_CASE(MINT_UNBOX)
3623 c = rtm->data_items[*(guint16 *)(ip + 1)];
3624
3625 o = sp [-1].data.p;
3626 if (!o)
3627 THROW_EX (mono_get_exception_null_reference (), ip);
3628
3629 MonoObject *isinst_obj = mono_object_isinst_checked (o, c, &error);
3630 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3631 if (!(isinst_obj || ((o->vtable->klass->rank == 0) && (o->vtable->klass->element_class == c->element_class))))
3632 THROW_EX (mono_get_exception_invalid_cast (), ip);
3633
3634 sp [-1].data.p = mono_object_unbox (o);
3635 ip += 2;
3636 MINT_IN_BREAK;
3637 MINT_IN_CASE(MINT_THROW)
3638 --sp;
3639 frame->ex_handler = NULL;
3640 if (!sp->data.p)
3641 sp->data.p = mono_get_exception_null_reference ();
3642
3643 THROW_EX ((MonoException *)sp->data.p, ip);
3644 MINT_IN_BREAK;
3645 MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
3646 o = sp [-1].data.p;
3647 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3648 ip += 2;
3649 MINT_IN_BREAK;
3650 MINT_IN_CASE(MINT_LDFLDA)
3651 o = sp [-1].data.p;
3652 if (!o)
3653 THROW_EX (mono_get_exception_null_reference (), ip);
3654 sp[-1].data.p = (char *)o + * (guint16 *)(ip + 1);
3655 ip += 2;
3656 MINT_IN_BREAK;
3657 MINT_IN_CASE(MINT_CKNULL)
3658 o = sp [-1].data.p;
3659 if (!o)
3660 THROW_EX (mono_get_exception_null_reference (), ip);
3661 ++ip;
3662 MINT_IN_BREAK;
3663 MINT_IN_CASE(MINT_CKNULL_N) {
3664 /* Same as CKNULL, but further down the stack */
3665 int n = *(guint16*)(ip + 1);
3666 o = sp [-n].data.p;
3667 if (!o)
3668 THROW_EX (mono_get_exception_null_reference (), ip);
3669 ip += 2;
3670 MINT_IN_BREAK;
3671 }
3672
3673 #define LDFLD(datamem, fieldtype) \
3674 o = sp [-1].data.p; \
3675 if (!o) \
3676 THROW_EX (mono_get_exception_null_reference (), ip); \
3677 sp[-1].data.datamem = * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) ; \
3678 ip += 2;
3679
3680 MINT_IN_CASE(MINT_LDFLD_I1) LDFLD(i, gint8); MINT_IN_BREAK;
3681 MINT_IN_CASE(MINT_LDFLD_U1) LDFLD(i, guint8); MINT_IN_BREAK;
3682 MINT_IN_CASE(MINT_LDFLD_I2) LDFLD(i, gint16); MINT_IN_BREAK;
3683 MINT_IN_CASE(MINT_LDFLD_U2) LDFLD(i, guint16); MINT_IN_BREAK;
3684 MINT_IN_CASE(MINT_LDFLD_I4) LDFLD(i, gint32); MINT_IN_BREAK;
3685 MINT_IN_CASE(MINT_LDFLD_I8) LDFLD(l, gint64); MINT_IN_BREAK;
3686 MINT_IN_CASE(MINT_LDFLD_R4) LDFLD(f, float); MINT_IN_BREAK;
3687 MINT_IN_CASE(MINT_LDFLD_R8) LDFLD(f, double); MINT_IN_BREAK;
3688 MINT_IN_CASE(MINT_LDFLD_O) LDFLD(p, gpointer); MINT_IN_BREAK;
3689 MINT_IN_CASE(MINT_LDFLD_P) LDFLD(p, gpointer); MINT_IN_BREAK;
3690
3691 MINT_IN_CASE(MINT_LDFLD_VT)
3692 o = sp [-1].data.p;
3693 if (!o)
3694 THROW_EX (mono_get_exception_null_reference (), ip);
3695
3696 MonoClassField *field = rtm->data_items[* (guint16 *)(ip + 2)];
3697 MonoClass *klass = mono_class_from_mono_type (field->type);
3698 i32 = mono_class_value_size (klass, NULL);
3699
3700 sp [-1].data.p = vt_sp;
3701 memcpy (sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3702 vt_sp += (i32 + 7) & ~7;
3703 ip += 3;
3704 MINT_IN_BREAK;
3705
3706 MINT_IN_CASE(MINT_LDRMFLD) {
3707 gpointer tmp;
3708 MonoClassField *field;
3709 char *addr;
3710
3711 o = sp [-1].data.p;
3712 if (!o)
3713 THROW_EX (mono_get_exception_null_reference (), ip);
3714 field = rtm->data_items[* (guint16 *)(ip + 1)];
3715 ip += 2;
3716 #ifndef DISABLE_REMOTING
3717 if (mono_object_is_transparent_proxy (o)) {
3718 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3719
3720 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3721 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3722 } else
3723 #endif
3724 addr = (char*)o + field->offset;
3725
3726 stackval_from_data (field->type, &sp [-1], addr, FALSE);
3727 MINT_IN_BREAK;
3728 }
3729
3730 MINT_IN_CASE(MINT_LDRMFLD_VT) {
3731 MonoClassField *field;
3732 char *addr;
3733 gpointer tmp;
3734
3735 o = sp [-1].data.p;
3736 if (!o)
3737 THROW_EX (mono_get_exception_null_reference (), ip);
3738
3739 field = rtm->data_items[* (guint16 *)(ip + 1)];
3740 MonoClass *klass = mono_class_from_mono_type (field->type);
3741 i32 = mono_class_value_size (klass, NULL);
3742
3743 ip += 2;
3744 #ifndef DISABLE_REMOTING
3745 if (mono_object_is_transparent_proxy (o)) {
3746 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3747 addr = mono_load_remote_field_checked (o, klass, field, &tmp, &error);
3748 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3749 } else
3750 #endif
3751 addr = (char*)o + field->offset;
3752
3753 sp [-1].data.p = vt_sp;
3754 memcpy(sp [-1].data.p, (char *)o + * (guint16 *)(ip + 1), i32);
3755 vt_sp += (i32 + 7) & ~7;
3756 memcpy(sp [-1].data.p, addr, i32);
3757 MINT_IN_BREAK;
3758 }
3759
3760 #define STFLD(datamem, fieldtype) \
3761 o = sp [-2].data.p; \
3762 if (!o) \
3763 THROW_EX (mono_get_exception_null_reference (), ip); \
3764 sp -= 2; \
3765 * (fieldtype *)((char *)o + * (guint16 *)(ip + 1)) = sp[1].data.datamem; \
3766 ip += 2;
3767
3768 MINT_IN_CASE(MINT_STFLD_I1) STFLD(i, gint8); MINT_IN_BREAK;
3769 MINT_IN_CASE(MINT_STFLD_U1) STFLD(i, guint8); MINT_IN_BREAK;
3770 MINT_IN_CASE(MINT_STFLD_I2) STFLD(i, gint16); MINT_IN_BREAK;
3771 MINT_IN_CASE(MINT_STFLD_U2) STFLD(i, guint16); MINT_IN_BREAK;
3772 MINT_IN_CASE(MINT_STFLD_I4) STFLD(i, gint32); MINT_IN_BREAK;
3773 MINT_IN_CASE(MINT_STFLD_I8) STFLD(l, gint64); MINT_IN_BREAK;
3774 MINT_IN_CASE(MINT_STFLD_R4) STFLD(f, float); MINT_IN_BREAK;
3775 MINT_IN_CASE(MINT_STFLD_R8) STFLD(f, double); MINT_IN_BREAK;
3776 MINT_IN_CASE(MINT_STFLD_P) STFLD(p, gpointer); MINT_IN_BREAK;
3777 MINT_IN_CASE(MINT_STFLD_O)
3778 o = sp [-2].data.p;
3779 if (!o)
3780 THROW_EX (mono_get_exception_null_reference (), ip);
3781 sp -= 2;
3782 mono_gc_wbarrier_set_field (o, (char *) o + * (guint16 *)(ip + 1), sp [1].data.p);
3783 ip += 2;
3784 MINT_IN_BREAK;
3785
3786 MINT_IN_CASE(MINT_STFLD_VT) {
3787 o = sp [-2].data.p;
3788 if (!o)
3789 THROW_EX (mono_get_exception_null_reference (), ip);
3790 sp -= 2;
3791
3792 MonoClassField *field = rtm->data_items[* (guint16 *)(ip + 2)];
3793 MonoClass *klass = mono_class_from_mono_type (field->type);
3794 i32 = mono_class_value_size (klass, NULL);
3795
3796 guint16 offset = * (guint16 *)(ip + 1);
3797 mono_value_copy ((char *) o + offset, sp [1].data.p, klass);
3798
3799 vt_sp -= (i32 + 7) & ~7;
3800 ip += 3;
3801 MINT_IN_BREAK;
3802 }
3803 MINT_IN_CASE(MINT_STRMFLD) {
3804 MonoClassField *field;
3805
3806 o = sp [-2].data.p;
3807 if (!o)
3808 THROW_EX (mono_get_exception_null_reference (), ip);
3809
3810 field = rtm->data_items[* (guint16 *)(ip + 1)];
3811 ip += 2;
3812
3813 #ifndef DISABLE_REMOTING
3814 if (mono_object_is_transparent_proxy (o)) {
3815 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3816 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3817 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3818 } else
3819 #endif
3820 stackval_to_data (field->type, &sp [-1], (char*)o + field->offset, FALSE);
3821
3822 sp -= 2;
3823 MINT_IN_BREAK;
3824 }
3825 MINT_IN_CASE(MINT_STRMFLD_VT) {
3826 MonoClassField *field;
3827
3828 o = sp [-2].data.p;
3829 if (!o)
3830 THROW_EX (mono_get_exception_null_reference (), ip);
3831 field = rtm->data_items[* (guint16 *)(ip + 1)];
3832 MonoClass *klass = mono_class_from_mono_type (field->type);
3833 i32 = mono_class_value_size (klass, NULL);
3834 ip += 2;
3835
3836 #ifndef DISABLE_REMOTING
3837 if (mono_object_is_transparent_proxy (o)) {
3838 MonoClass *klass = ((MonoTransparentProxy*)o)->remote_class->proxy_class;
3839 mono_store_remote_field_checked (o, klass, field, &sp [-1].data, &error);
3840 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3841 } else
3842 #endif
3843 mono_value_copy ((char *) o + field->offset, sp [-1].data.p, klass);
3844
3845 sp -= 2;
3846 vt_sp -= (i32 + 7) & ~7;
3847 MINT_IN_BREAK;
3848 }
3849 MINT_IN_CASE(MINT_LDSFLDA) {
3850 MonoClassField *field = rtm->data_items[*(guint16 *)(ip + 1)];
3851 sp->data.p = mono_class_static_field_address (rtm->domain, field);
3852 ip += 2;
3853 ++sp;
3854 MINT_IN_BREAK;
3855 }
3856 MINT_IN_CASE(MINT_LDSFLD) {
3857 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3858 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3859 stackval_from_data (field->type, sp, addr, FALSE);
3860 ip += 2;
3861 ++sp;
3862 MINT_IN_BREAK;
3863 }
3864 MINT_IN_CASE(MINT_LDSFLD_VT) {
3865 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3866 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3867 int size = READ32 (ip + 2);
3868 ip += 4;
3869
3870 sp->data.p = vt_sp;
3871 vt_sp += (size + 7) & ~7;
3872 stackval_from_data (field->type, sp, addr, FALSE);
3873 ++sp;
3874 MINT_IN_BREAK;
3875 }
3876 MINT_IN_CASE(MINT_STSFLD) {
3877 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3878 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3879 ip += 2;
3880 --sp;
3881 stackval_to_data (field->type, sp, addr, FALSE);
3882 MINT_IN_BREAK;
3883 }
3884 MINT_IN_CASE(MINT_STSFLD_VT) {
3885 MonoClassField *field = rtm->data_items [* (guint16 *)(ip + 1)];
3886 gpointer addr = mono_class_static_field_address (rtm->domain, field);
3887 MonoClass *klass = mono_class_from_mono_type (field->type);
3888 i32 = mono_class_value_size (klass, NULL);
3889 ip += 2;
3890
3891 --sp;
3892 stackval_to_data (field->type, sp, addr, FALSE);
3893 vt_sp -= (i32 + 7) & ~7;
3894 MINT_IN_BREAK;
3895 }
3896 MINT_IN_CASE(MINT_STOBJ_VT) {
3897 int size;
3898 c = rtm->data_items[* (guint16 *)(ip + 1)];
3899 ip += 2;
3900 size = mono_class_value_size (c, NULL);
3901 memcpy(sp [-2].data.p, sp [-1].data.p, size);
3902 vt_sp -= (size + 7) & ~7;
3903 sp -= 2;
3904 MINT_IN_BREAK;
3905 }
3906 MINT_IN_CASE(MINT_STOBJ) {
3907 c = rtm->data_items[* (guint16 *)(ip + 1)];
3908 ip += 2;
3909
3910 g_assert (!c->byval_arg.byref);
3911 if (MONO_TYPE_IS_REFERENCE (&c->byval_arg))
3912 mono_gc_wbarrier_generic_store (sp [-2].data.p, sp [-1].data.p);
3913 else
3914 stackval_from_data (&c->byval_arg, sp [-2].data.p, (char *) &sp [-1].data.p, FALSE);
3915 sp -= 2;
3916 MINT_IN_BREAK;
3917 }
3918 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_R8)
3919 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
3920 THROW_EX (mono_get_exception_overflow (), ip);
3921 sp [-1].data.i = (guint32)sp [-1].data.f;
3922 ++ip;
3923 MINT_IN_BREAK;
3924 MINT_IN_CASE(MINT_CONV_OVF_U8_I4)
3925 if (sp [-1].data.i < 0)
3926 THROW_EX (mono_get_exception_overflow (), ip);
3927 sp [-1].data.l = sp [-1].data.i;
3928 ++ip;
3929 MINT_IN_BREAK;
3930 MINT_IN_CASE(MINT_CONV_OVF_U8_I8)
3931 if (sp [-1].data.l < 0)
3932 THROW_EX (mono_get_exception_overflow (), ip);
3933 ++ip;
3934 MINT_IN_BREAK;
3935 MINT_IN_CASE(MINT_CONV_OVF_I8_U8)
3936 if ((guint64) sp [-1].data.l > MYGINT64_MAX)
3937 THROW_EX (mono_get_exception_overflow (), ip);
3938 ++ip;
3939 MINT_IN_BREAK;
3940 MINT_IN_CASE(MINT_CONV_OVF_U8_R8)
3941 MINT_IN_CASE(MINT_CONV_OVF_I8_UN_R8)
3942 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGINT64_MAX)
3943 THROW_EX (mono_get_exception_overflow (), ip);
3944 sp [-1].data.l = (guint64)sp [-1].data.f;
3945 ++ip;
3946 MINT_IN_BREAK;
3947 MINT_IN_CASE(MINT_CONV_OVF_I8_R8)
3948 if (sp [-1].data.f < MYGINT64_MIN || sp [-1].data.f > MYGINT64_MAX)
3949 THROW_EX (mono_get_exception_overflow (), ip);
3950 sp [-1].data.l = (gint64)sp [-1].data.f;
3951 ++ip;
3952 MINT_IN_BREAK;
3953 MINT_IN_CASE(MINT_CONV_OVF_I4_UN_I8)
3954 if ((mono_u)sp [-1].data.l > MYGUINT32_MAX)
3955 THROW_EX (mono_get_exception_overflow (), ip);
3956 sp [-1].data.i = (mono_u)sp [-1].data.l;
3957 ++ip;
3958 MINT_IN_BREAK;
3959 MINT_IN_CASE(MINT_BOX) {
3960 c = rtm->data_items [* (guint16 *)(ip + 1)];
3961 guint16 offset = * (guint16 *)(ip + 2);
3962 gboolean pop_vt_sp = !(offset & BOX_NOT_CLEAR_VT_SP);
3963 offset &= ~BOX_NOT_CLEAR_VT_SP;
3964
3965 if (mint_type (&c->byval_arg) == MINT_TYPE_VT && !c->enumtype && !(mono_class_is_magic_int (c) || mono_class_is_magic_float (c))) {
3966 int size = mono_class_value_size (c, NULL);
3967 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, sp [-1 - offset].data.p, &error);
3968 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3969 size = (size + 7) & ~7;
3970 if (pop_vt_sp)
3971 vt_sp -= size;
3972 } else {
3973 stackval_to_data (&c->byval_arg, &sp [-1 - offset], (char *) &sp [-1 - offset], FALSE);
3974 sp [-1 - offset].data.p = mono_value_box_checked (rtm->domain, c, &sp [-1 - offset], &error);
3975 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3976 }
3977 ip += 3;
3978 MINT_IN_BREAK;
3979 }
3980 MINT_IN_CASE(MINT_NEWARR)
3981 sp [-1].data.p = (MonoObject*) mono_array_new_checked (rtm->domain, rtm->data_items[*(guint16 *)(ip + 1)], sp [-1].data.i, &error);
3982 if (!mono_error_ok (&error)) {
3983 THROW_EX (mono_error_convert_to_exception (&error), ip);
3984 }
3985 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
3986 ip += 2;
3987 /*if (profiling_classes) {
3988 guint count = GPOINTER_TO_UINT (g_hash_table_lookup (profiling_classes, o->vtable->klass));
3989 count++;
3990 g_hash_table_insert (profiling_classes, o->vtable->klass, GUINT_TO_POINTER (count));
3991 }*/
3992
3993 MINT_IN_BREAK;
3994 MINT_IN_CASE(MINT_LDLEN)
3995 o = sp [-1].data.p;
3996 if (!o)
3997 THROW_EX (mono_get_exception_null_reference (), ip);
3998 sp [-1].data.nati = mono_array_length ((MonoArray *)o);
3999 ++ip;
4000 MINT_IN_BREAK;
4001 MINT_IN_CASE(MINT_GETCHR) {
4002 MonoString *s;
4003 s = sp [-2].data.p;
4004 if (!s)
4005 THROW_EX (mono_get_exception_null_reference (), ip);
4006 i32 = sp [-1].data.i;
4007 if (i32 < 0 || i32 >= mono_string_length (s))
4008 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4009 --sp;
4010 sp [-1].data.i = mono_string_chars(s)[i32];
4011 ++ip;
4012 MINT_IN_BREAK;
4013 }
4014 MINT_IN_CASE(MINT_STRLEN)
4015 ++ip;
4016 o = sp [-1].data.p;
4017 if (!o)
4018 THROW_EX (mono_get_exception_null_reference (), ip);
4019 sp [-1].data.i = mono_string_length ((MonoString*) o);
4020 MINT_IN_BREAK;
4021 MINT_IN_CASE(MINT_ARRAY_RANK)
4022 o = sp [-1].data.p;
4023 if (!o)
4024 THROW_EX (mono_get_exception_null_reference (), ip);
4025 sp [-1].data.i = mono_object_class (sp [-1].data.p)->rank;
4026 ip++;
4027 MINT_IN_BREAK;
4028 MINT_IN_CASE(MINT_LDELEMA)
4029 MINT_IN_CASE(MINT_LDELEMA_TC) {
4030 gboolean needs_typecheck = *ip == MINT_LDELEMA_TC;
4031
4032 MonoClass *klass = rtm->data_items [*(guint16 *) (ip + 1)];
4033 guint16 numargs = *(guint16 *) (ip + 2);
4034 ip += 3;
4035 sp -= numargs;
4036
4037 o = sp [0].data.p;
4038 sp->data.p = ves_array_element_address (frame, klass, (MonoArray *) o, &sp [1], needs_typecheck);
4039 if (frame->ex)
4040 THROW_EX (frame->ex, ip);
4041 ++sp;
4042
4043 MINT_IN_BREAK;
4044 }
4045 MINT_IN_CASE(MINT_LDELEM_I1) /* fall through */
4046 MINT_IN_CASE(MINT_LDELEM_U1) /* fall through */
4047 MINT_IN_CASE(MINT_LDELEM_I2) /* fall through */
4048 MINT_IN_CASE(MINT_LDELEM_U2) /* fall through */
4049 MINT_IN_CASE(MINT_LDELEM_I4) /* fall through */
4050 MINT_IN_CASE(MINT_LDELEM_U4) /* fall through */
4051 MINT_IN_CASE(MINT_LDELEM_I8) /* fall through */
4052 MINT_IN_CASE(MINT_LDELEM_I) /* fall through */
4053 MINT_IN_CASE(MINT_LDELEM_R4) /* fall through */
4054 MINT_IN_CASE(MINT_LDELEM_R8) /* fall through */
4055 MINT_IN_CASE(MINT_LDELEM_REF) /* fall through */
4056 MINT_IN_CASE(MINT_LDELEM_VT) {
4057 MonoArray *o;
4058 mono_u aindex;
4059
4060 sp -= 2;
4061
4062 o = sp [0].data.p;
4063 if (!o)
4064 THROW_EX (mono_get_exception_null_reference (), ip);
4065
4066 aindex = sp [1].data.i;
4067 if (aindex >= mono_array_length (o))
4068 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4069
4070 /*
4071 * FIXME: throw mono_get_exception_array_type_mismatch () if needed
4072 */
4073 switch (*ip) {
4074 case MINT_LDELEM_I1:
4075 sp [0].data.i = mono_array_get (o, gint8, aindex);
4076 break;
4077 case MINT_LDELEM_U1:
4078 sp [0].data.i = mono_array_get (o, guint8, aindex);
4079 break;
4080 case MINT_LDELEM_I2:
4081 sp [0].data.i = mono_array_get (o, gint16, aindex);
4082 break;
4083 case MINT_LDELEM_U2:
4084 sp [0].data.i = mono_array_get (o, guint16, aindex);
4085 break;
4086 case MINT_LDELEM_I:
4087 sp [0].data.nati = mono_array_get (o, mono_i, aindex);
4088 break;
4089 case MINT_LDELEM_I4:
4090 sp [0].data.i = mono_array_get (o, gint32, aindex);
4091 break;
4092 case MINT_LDELEM_U4:
4093 sp [0].data.i = mono_array_get (o, guint32, aindex);
4094 break;
4095 case MINT_LDELEM_I8:
4096 sp [0].data.l = mono_array_get (o, guint64, aindex);
4097 break;
4098 case MINT_LDELEM_R4:
4099 sp [0].data.f = mono_array_get (o, float, aindex);
4100 break;
4101 case MINT_LDELEM_R8:
4102 sp [0].data.f = mono_array_get (o, double, aindex);
4103 break;
4104 case MINT_LDELEM_REF:
4105 sp [0].data.p = mono_array_get (o, gpointer, aindex);
4106 break;
4107 case MINT_LDELEM_VT: {
4108 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4109 i32 = READ32 (ip + 2);
4110 char *src_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4111 sp [0].data.vt = vt_sp;
4112 stackval_from_data (&klass_vt->byval_arg, sp, src_addr, FALSE);
4113 vt_sp += (i32 + 7) & ~7;
4114 ip += 3;
4115 break;
4116 }
4117 default:
4118 ves_abort();
4119 }
4120
4121 ++ip;
4122 ++sp;
4123 MINT_IN_BREAK;
4124 }
4125 MINT_IN_CASE(MINT_STELEM_I) /* fall through */
4126 MINT_IN_CASE(MINT_STELEM_I1) /* fall through */
4127 MINT_IN_CASE(MINT_STELEM_U1) /* fall through */
4128 MINT_IN_CASE(MINT_STELEM_I2) /* fall through */
4129 MINT_IN_CASE(MINT_STELEM_U2) /* fall through */
4130 MINT_IN_CASE(MINT_STELEM_I4) /* fall through */
4131 MINT_IN_CASE(MINT_STELEM_I8) /* fall through */
4132 MINT_IN_CASE(MINT_STELEM_R4) /* fall through */
4133 MINT_IN_CASE(MINT_STELEM_R8) /* fall through */
4134 MINT_IN_CASE(MINT_STELEM_REF) /* fall through */
4135 MINT_IN_CASE(MINT_STELEM_VT) {
4136 mono_u aindex;
4137
4138 sp -= 3;
4139
4140 o = sp [0].data.p;
4141 if (!o)
4142 THROW_EX (mono_get_exception_null_reference (), ip);
4143
4144 aindex = sp [1].data.i;
4145 if (aindex >= mono_array_length ((MonoArray *)o))
4146 THROW_EX (mono_get_exception_index_out_of_range (), ip);
4147
4148 switch (*ip) {
4149 case MINT_STELEM_I:
4150 mono_array_set ((MonoArray *)o, mono_i, aindex, sp [2].data.nati);
4151 break;
4152 case MINT_STELEM_I1:
4153 mono_array_set ((MonoArray *)o, gint8, aindex, sp [2].data.i);
4154 break;
4155 case MINT_STELEM_U1:
4156 mono_array_set ((MonoArray *) o, guint8, aindex, sp [2].data.i);
4157 break;
4158 case MINT_STELEM_I2:
4159 mono_array_set ((MonoArray *)o, gint16, aindex, sp [2].data.i);
4160 break;
4161 case MINT_STELEM_U2:
4162 mono_array_set ((MonoArray *)o, guint16, aindex, sp [2].data.i);
4163 break;
4164 case MINT_STELEM_I4:
4165 mono_array_set ((MonoArray *)o, gint32, aindex, sp [2].data.i);
4166 break;
4167 case MINT_STELEM_I8:
4168 mono_array_set ((MonoArray *)o, gint64, aindex, sp [2].data.l);
4169 break;
4170 case MINT_STELEM_R4:
4171 mono_array_set ((MonoArray *)o, float, aindex, sp [2].data.f);
4172 break;
4173 case MINT_STELEM_R8:
4174 mono_array_set ((MonoArray *)o, double, aindex, sp [2].data.f);
4175 break;
4176 case MINT_STELEM_REF: {
4177 MonoObject *isinst_obj = mono_object_isinst_checked (sp [2].data.p, mono_object_class (o)->element_class, &error);
4178 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4179 if (sp [2].data.p && !isinst_obj)
4180 THROW_EX (mono_get_exception_array_type_mismatch (), ip);
4181 mono_array_setref ((MonoArray *) o, aindex, sp [2].data.p);
4182 break;
4183 }
4184 case MINT_STELEM_VT: {
4185 MonoClass *klass_vt = rtm->data_items [*(guint16 *) (ip + 1)];
4186 i32 = READ32 (ip + 2);
4187 char *dst_addr = mono_array_addr_with_size ((MonoArray *) o, i32, aindex);
4188
4189 stackval_to_data (&klass_vt->byval_arg, &sp [2], dst_addr, FALSE);
4190 vt_sp -= (i32 + 7) & ~7;
4191 ip += 3;
4192 break;
4193 }
4194 default:
4195 ves_abort();
4196 }
4197
4198 ++ip;
4199 MINT_IN_BREAK;
4200 }
4201 MINT_IN_CASE(MINT_CONV_OVF_I4_U4)
4202 if (sp [-1].data.i < 0)
4203 THROW_EX (mono_get_exception_overflow (), ip);
4204 ++ip;
4205 MINT_IN_BREAK;
4206 MINT_IN_CASE(MINT_CONV_OVF_I4_I8)
4207 if (sp [-1].data.l < MYGINT32_MIN || sp [-1].data.l > MYGINT32_MAX)
4208 THROW_EX (mono_get_exception_overflow (), ip);
4209 sp [-1].data.i = (gint32) sp [-1].data.l;
4210 ++ip;
4211 MINT_IN_BREAK;
4212 MINT_IN_CASE(MINT_CONV_OVF_I4_U8)
4213 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGINT32_MAX)
4214 THROW_EX (mono_get_exception_overflow (), ip);
4215 sp [-1].data.i = (gint32) sp [-1].data.l;
4216 ++ip;
4217 MINT_IN_BREAK;
4218 MINT_IN_CASE(MINT_CONV_OVF_I4_R8)
4219 if (sp [-1].data.f < MYGINT32_MIN || sp [-1].data.f > MYGINT32_MAX)
4220 THROW_EX (mono_get_exception_overflow (), ip);
4221 sp [-1].data.i = (gint32) sp [-1].data.f;
4222 ++ip;
4223 MINT_IN_BREAK;
4224 MINT_IN_CASE(MINT_CONV_OVF_U4_I4)
4225 if (sp [-1].data.i < 0)
4226 THROW_EX (mono_get_exception_overflow (), ip);
4227 ++ip;
4228 MINT_IN_BREAK;
4229 MINT_IN_CASE(MINT_CONV_OVF_U4_I8)
4230 if (sp [-1].data.l < 0 || sp [-1].data.l > MYGUINT32_MAX)
4231 THROW_EX (mono_get_exception_overflow (), ip);
4232 sp [-1].data.i = (guint32) sp [-1].data.l;
4233 ++ip;
4234 MINT_IN_BREAK;
4235 MINT_IN_CASE(MINT_CONV_OVF_U4_R8)
4236 if (sp [-1].data.f < 0 || sp [-1].data.f > MYGUINT32_MAX)
4237 THROW_EX (mono_get_exception_overflow (), ip);
4238 sp [-1].data.i = (guint32) sp [-1].data.f;
4239 ++ip;
4240 MINT_IN_BREAK;
4241 MINT_IN_CASE(MINT_CONV_OVF_I2_I4)
4242 if (sp [-1].data.i < -32768 || sp [-1].data.i > 32767)
4243 THROW_EX (mono_get_exception_overflow (), ip);
4244 ++ip;
4245 MINT_IN_BREAK;
4246 MINT_IN_CASE(MINT_CONV_OVF_I2_I8)
4247 if (sp [-1].data.l < -32768 || sp [-1].data.l > 32767)
4248 THROW_EX (mono_get_exception_overflow (), ip);
4249 sp [-1].data.i = (gint16) sp [-1].data.l;
4250 ++ip;
4251 MINT_IN_BREAK;
4252 MINT_IN_CASE(MINT_CONV_OVF_I2_R8)
4253 if (sp [-1].data.f < -32768 || sp [-1].data.f > 32767)
4254 THROW_EX (mono_get_exception_overflow (), ip);
4255 sp [-1].data.i = (gint16) sp [-1].data.f;
4256 ++ip;
4257 MINT_IN_BREAK;
4258 MINT_IN_CASE(MINT_CONV_OVF_U2_I4)
4259 if (sp [-1].data.i < 0 || sp [-1].data.i > 65535)
4260 THROW_EX (mono_get_exception_overflow (), ip);
4261 ++ip;
4262 MINT_IN_BREAK;
4263 MINT_IN_CASE(MINT_CONV_OVF_U2_I8)
4264 if (sp [-1].data.l < 0 || sp [-1].data.l > 65535)
4265 THROW_EX (mono_get_exception_overflow (), ip);
4266 sp [-1].data.i = (guint16) sp [-1].data.l;
4267 ++ip;
4268 MINT_IN_BREAK;
4269 MINT_IN_CASE(MINT_CONV_OVF_U2_R8)
4270 if (sp [-1].data.f < 0 || sp [-1].data.f > 65535)
4271 THROW_EX (mono_get_exception_overflow (), ip);
4272 sp [-1].data.i = (guint16) sp [-1].data.f;
4273 ++ip;
4274 MINT_IN_BREAK;
4275 MINT_IN_CASE(MINT_CONV_OVF_I1_I4)
4276 if (sp [-1].data.i < -128 || sp [-1].data.i > 127)
4277 THROW_EX (mono_get_exception_overflow (), ip);
4278 ++ip;
4279 MINT_IN_BREAK;
4280 MINT_IN_CASE(MINT_CONV_OVF_I1_I8)
4281 if (sp [-1].data.l < -128 || sp [-1].data.l > 127)
4282 THROW_EX (mono_get_exception_overflow (), ip);
4283 sp [-1].data.i = (gint8) sp [-1].data.l;
4284 ++ip;
4285 MINT_IN_BREAK;
4286 MINT_IN_CASE(MINT_CONV_OVF_I1_R8)
4287 if (sp [-1].data.f < -128 || sp [-1].data.f > 127)
4288 THROW_EX (mono_get_exception_overflow (), ip);
4289 sp [-1].data.i = (gint8) sp [-1].data.f;
4290 ++ip;
4291 MINT_IN_BREAK;
4292 MINT_IN_CASE(MINT_CONV_OVF_U1_I4)
4293 if (sp [-1].data.i < 0 || sp [-1].data.i > 255)
4294 THROW_EX (mono_get_exception_overflow (), ip);
4295 ++ip;
4296 MINT_IN_BREAK;
4297 MINT_IN_CASE(MINT_CONV_OVF_U1_I8)
4298 if (sp [-1].data.l < 0 || sp [-1].data.l > 255)
4299 THROW_EX (mono_get_exception_overflow (), ip);
4300 sp [-1].data.i = (guint8) sp [-1].data.l;
4301 ++ip;
4302 MINT_IN_BREAK;
4303 MINT_IN_CASE(MINT_CONV_OVF_U1_R8)
4304 if (sp [-1].data.f < 0 || sp [-1].data.f > 255)
4305 THROW_EX (mono_get_exception_overflow (), ip);
4306 sp [-1].data.i = (guint8) sp [-1].data.f;
4307 ++ip;
4308 MINT_IN_BREAK;
4309 #if 0
4310 MINT_IN_CASE(MINT_LDELEM)
4311 MINT_IN_CASE(MINT_STELEM)
4312 MINT_IN_CASE(MINT_UNBOX_ANY)
4313 #endif
4314 MINT_IN_CASE(MINT_CKFINITE)
4315 if (!isfinite(sp [-1].data.f))
4316 THROW_EX (mono_get_exception_arithmetic (), ip);
4317 ++ip;
4318 MINT_IN_BREAK;
4319 MINT_IN_CASE(MINT_MKREFANY) {
4320 c = rtm->data_items [*(guint16 *)(ip + 1)];
4321
4322 /* The value address is on the stack */
4323 gpointer addr = sp [-1].data.p;
4324 /* Push the typedref value on the stack */
4325 sp [-1].data.p = vt_sp;
4326 vt_sp += sizeof (MonoTypedRef);
4327
4328 MonoTypedRef *tref = sp [-1].data.p;
4329 tref->klass = c;
4330 tref->type = &c->byval_arg;
4331 tref->value = addr;
4332
4333 ip += 2;
4334 MINT_IN_BREAK;
4335 }
4336 MINT_IN_CASE(MINT_REFANYTYPE) {
4337 MonoTypedRef *tref = sp [-1].data.p;
4338 MonoType *type = tref->type;
4339
4340 vt_sp -= sizeof (MonoTypedRef);
4341 sp [-1].data.p = vt_sp;
4342 vt_sp += 8;
4343 *(gpointer*)sp [-1].data.p = type;
4344 ip ++;
4345 MINT_IN_BREAK;
4346 }
4347 MINT_IN_CASE(MINT_REFANYVAL) {
4348 MonoTypedRef *tref = sp [-1].data.p;
4349 gpointer addr = tref->value;
4350
4351 vt_sp -= sizeof (MonoTypedRef);
4352
4353 sp [-1].data.p = addr;
4354 ip ++;
4355 MINT_IN_BREAK;
4356 }
4357 MINT_IN_CASE(MINT_LDTOKEN)
4358 sp->data.p = vt_sp;
4359 vt_sp += 8;
4360 * (gpointer *)sp->data.p = rtm->data_items[*(guint16 *)(ip + 1)];
4361 ip += 2;
4362 ++sp;
4363 MINT_IN_BREAK;
4364 MINT_IN_CASE(MINT_ADD_OVF_I4)
4365 if (CHECK_ADD_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4366 THROW_EX (mono_get_exception_overflow (), ip);
4367 BINOP(i, +);
4368 MINT_IN_BREAK;
4369 MINT_IN_CASE(MINT_ADD_OVF_I8)
4370 if (CHECK_ADD_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4371 THROW_EX (mono_get_exception_overflow (), ip);
4372 BINOP(l, +);
4373 MINT_IN_BREAK;
4374 MINT_IN_CASE(MINT_ADD_OVF_UN_I4)
4375 if (CHECK_ADD_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4376 THROW_EX (mono_get_exception_overflow (), ip);
4377 BINOP_CAST(i, +, guint32);
4378 MINT_IN_BREAK;
4379 MINT_IN_CASE(MINT_ADD_OVF_UN_I8)
4380 if (CHECK_ADD_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4381 THROW_EX (mono_get_exception_overflow (), ip);
4382 BINOP_CAST(l, +, guint64);
4383 MINT_IN_BREAK;
4384 MINT_IN_CASE(MINT_MUL_OVF_I4)
4385 if (CHECK_MUL_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4386 THROW_EX (mono_get_exception_overflow (), ip);
4387 BINOP(i, *);
4388 MINT_IN_BREAK;
4389 MINT_IN_CASE(MINT_MUL_OVF_I8)
4390 if (CHECK_MUL_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4391 THROW_EX (mono_get_exception_overflow (), ip);
4392 BINOP(l, *);
4393 MINT_IN_BREAK;
4394 MINT_IN_CASE(MINT_MUL_OVF_UN_I4)
4395 if (CHECK_MUL_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4396 THROW_EX (mono_get_exception_overflow (), ip);
4397 BINOP_CAST(i, *, guint32);
4398 MINT_IN_BREAK;
4399 MINT_IN_CASE(MINT_MUL_OVF_UN_I8)
4400 if (CHECK_MUL_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4401 THROW_EX (mono_get_exception_overflow (), ip);
4402 BINOP_CAST(l, *, guint64);
4403 MINT_IN_BREAK;
4404 MINT_IN_CASE(MINT_SUB_OVF_I4)
4405 if (CHECK_SUB_OVERFLOW (sp [-2].data.i, sp [-1].data.i))
4406 THROW_EX (mono_get_exception_overflow (), ip);
4407 BINOP(i, -);
4408 MINT_IN_BREAK;
4409 MINT_IN_CASE(MINT_SUB_OVF_I8)
4410 if (CHECK_SUB_OVERFLOW64 (sp [-2].data.l, sp [-1].data.l))
4411 THROW_EX (mono_get_exception_overflow (), ip);
4412 BINOP(l, -);
4413 MINT_IN_BREAK;
4414 MINT_IN_CASE(MINT_SUB_OVF_UN_I4)
4415 if (CHECK_SUB_OVERFLOW_UN (sp [-2].data.i, sp [-1].data.i))
4416 THROW_EX (mono_get_exception_overflow (), ip);
4417 BINOP_CAST(i, -, guint32);
4418 MINT_IN_BREAK;
4419 MINT_IN_CASE(MINT_SUB_OVF_UN_I8)
4420 if (CHECK_SUB_OVERFLOW64_UN (sp [-2].data.l, sp [-1].data.l))
4421 THROW_EX (mono_get_exception_overflow (), ip);
4422 BINOP_CAST(l, -, guint64);
4423 MINT_IN_BREAK;
4424 MINT_IN_CASE(MINT_ENDFINALLY)
4425 ip ++;
4426 int clause_index = *ip;
4427 if (clause_index == exit_at_finally)
4428 goto exit_frame;
4429 while (sp > frame->stack) {
4430 --sp;
4431 }
4432 if (finally_ips) {
4433 ip = finally_ips->data;
4434 finally_ips = g_slist_remove (finally_ips, ip);
4435 goto main_loop;
4436 }
4437 if (frame->ex)
4438 goto handle_catch;
4439 ves_abort();
4440 MINT_IN_BREAK;
4441 MINT_IN_CASE(MINT_LEAVE) /* Fall through */
4442 MINT_IN_CASE(MINT_LEAVE_S)
4443 while (sp > frame->stack) {
4444 --sp;
4445 }
4446 frame->ip = ip;
4447
4448 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4449 frame->ex_handler = NULL;
4450 frame->ex = NULL;
4451 if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
4452 MonoException *abort_exc = mono_thread_get_undeniable_exception ();
4453 if (abort_exc)
4454 THROW_EX (abort_exc, frame->ip);
4455 }
4456
4457 }
4458
4459 if (*ip == MINT_LEAVE_S) {
4460 ip += (short) *(ip + 1);
4461 } else {
4462 ip += (gint32) READ32 (ip + 1);
4463 }
4464 endfinally_ip = ip;
4465 goto handle_finally;
4466 MINT_IN_BREAK;
4467 MINT_IN_CASE(MINT_LEAVE_CHECK)
4468 MINT_IN_CASE(MINT_LEAVE_S_CHECK)
4469 while (sp > frame->stack) {
4470 --sp;
4471 }
4472 frame->ip = ip;
4473
4474 if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) {
4475 frame->ex_handler = NULL;
4476 frame->ex = NULL;
4477 }
4478
4479 if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
4480 MonoException *abort_exc = mono_thread_get_undeniable_exception ();
4481 if (abort_exc)
4482 THROW_EX (abort_exc, frame->ip);
4483 }
4484
4485 if (*ip == MINT_LEAVE_S_CHECK) {
4486 ip += (short) *(ip + 1);
4487 } else {
4488 ip += (gint32) READ32 (ip + 1);
4489 }
4490 endfinally_ip = ip;
4491 goto handle_finally;
4492 MINT_IN_BREAK;
4493 MINT_IN_CASE(MINT_ICALL_V_V)
4494 MINT_IN_CASE(MINT_ICALL_V_P)
4495 MINT_IN_CASE(MINT_ICALL_P_V)
4496 MINT_IN_CASE(MINT_ICALL_P_P)
4497 MINT_IN_CASE(MINT_ICALL_PP_V)
4498 MINT_IN_CASE(MINT_ICALL_PI_V)
4499 MINT_IN_CASE(MINT_ICALL_PP_P)
4500 MINT_IN_CASE(MINT_ICALL_PI_P)
4501 MINT_IN_CASE(MINT_ICALL_PPP_V)
4502 MINT_IN_CASE(MINT_ICALL_PPI_V)
4503 sp = do_icall (context, *ip, sp, rtm->data_items [*(guint16 *)(ip + 1)]);
4504 if (*mono_thread_interruption_request_flag ()) {
4505 MonoException *exc = mono_thread_interruption_checkpoint ();
4506 if (exc)
4507 THROW_EX (exc, ip);
4508 }
4509 if (context->has_resume_state) {
4510 if (frame == context->handler_frame)
4511 SET_RESUME_STATE (context);
4512 else
4513 goto exit_frame;
4514 }
4515 ip += 2;
4516 MINT_IN_BREAK;
4517 MINT_IN_CASE(MINT_MONO_LDPTR)
4518 sp->data.p = rtm->data_items [*(guint16 *)(ip + 1)];
4519 ip += 2;
4520 ++sp;
4521 MINT_IN_BREAK;
4522 MINT_IN_CASE(MINT_MONO_NEWOBJ)
4523 sp->data.p = mono_object_new_checked (rtm->domain, rtm->data_items [*(guint16 *)(ip + 1)], &error);
4524 mono_error_cleanup (&error); /* FIXME: don't swallow the error */
4525 ip += 2;
4526 sp++;
4527 MINT_IN_BREAK;
4528 MINT_IN_CASE(MINT_MONO_FREE)
4529 ++ip;
4530 --sp;
4531 g_error ("that doesn't seem right");
4532 g_free (sp->data.p);
4533 MINT_IN_BREAK;
4534 MINT_IN_CASE(MINT_MONO_RETOBJ)
4535 ++ip;
4536 sp--;
4537 stackval_from_data (mono_method_signature (frame->imethod->method)->ret, frame->retval, sp->data.p,
4538 mono_method_signature (frame->imethod->method)->pinvoke);
4539 if (sp > frame->stack)
4540 g_warning ("retobj: more values on stack: %d", sp-frame->stack);
4541 goto exit_frame;
4542 MINT_IN_CASE(MINT_MONO_TLS) {
4543 MonoTlsKey key = *(gint32 *)(ip + 1);
4544 sp->data.p = ((gpointer (*)(void)) mono_tls_get_tls_getter (key, FALSE)) ();
4545 sp++;
4546 ip += 3;
4547 MINT_IN_BREAK;
4548 }
4549 MINT_IN_CASE(MINT_MONO_MEMORY_BARRIER) {
4550 ++ip;
4551 mono_memory_barrier ();
4552 MINT_IN_BREAK;
4553 }
4554 MINT_IN_CASE(MINT_MONO_JIT_ATTACH) {
4555 ++ip;
4556
4557 context->original_domain = NULL;
4558 MonoDomain *tls_domain = (MonoDomain *) ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_DOMAIN, FALSE)) ();
4559 gpointer tls_jit = ((gpointer (*)(void)) mono_tls_get_tls_getter (TLS_KEY_JIT_TLS, FALSE)) ();
4560
4561 if (tls_domain != rtm->domain || !tls_jit)
4562 context->original_domain = mono_jit_thread_attach (rtm->domain);
4563 MINT_IN_BREAK;
4564 }
4565 MINT_IN_CASE(MINT_MONO_JIT_DETACH)
4566 ++ip;
4567 mono_jit_set_domain (context->original_domain);
4568 MINT_IN_BREAK;
4569 MINT_IN_CASE(MINT_MONO_LDDOMAIN)
4570 sp->data.p = mono_domain_get ();
4571 ++sp;
4572 ++ip;
4573 MINT_IN_BREAK;
4574 MINT_IN_CASE(MINT_SDB_INTR_LOC)
4575 if (G_UNLIKELY (ss_enabled)) {
4576 static void (*ss_tramp) (void);
4577
4578 if (!ss_tramp) {
4579 void *tramp = mini_get_single_step_trampoline ();
4580 mono_memory_barrier ();
4581 ss_tramp = tramp;
4582 }
4583
4584 /*
4585 * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
4586 * the address of that instruction is stored as the seq point address.
4587 */
4588 frame->ip = ip + 1;
4589
4590 /*
4591 * Use the same trampoline as the JIT. This ensures that
4592 * the debugger has the context for the last interpreter
4593 * native frame.
4594 */
4595 do_debugger_tramp (ss_tramp, frame);
4596
4597 if (context->has_resume_state) {
4598 if (frame == context->handler_frame)
4599 SET_RESUME_STATE (context);
4600 else
4601 goto exit_frame;
4602 }
4603 }
4604 ++ip;
4605 MINT_IN_BREAK;
4606 MINT_IN_CASE(MINT_SDB_SEQ_POINT)
4607 /* Just a placeholder for a breakpoint */
4608 ++ip;
4609 MINT_IN_BREAK;
4610 MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
4611 static void (*bp_tramp) (void);
4612 if (!bp_tramp) {
4613 void *tramp = mini_get_breakpoint_trampoline ();
4614 mono_memory_barrier ();
4615 bp_tramp = tramp;
4616 }
4617
4618 frame->ip = ip;
4619
4620 /* Use the same trampoline as the JIT */
4621 do_debugger_tramp (bp_tramp, frame);
4622
4623 if (context->has_resume_state) {
4624 if (frame == context->handler_frame)
4625 SET_RESUME_STATE (context);
4626 else
4627 goto exit_frame;
4628 }
4629
4630 ++ip;
4631 MINT_IN_BREAK;
4632 }
4633
4634 #define RELOP(datamem, op) \
4635 --sp; \
4636 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4637 ++ip;
4638
4639 #define RELOP_FP(datamem, op, noorder) \
4640 --sp; \
4641 if (isunordered (sp [-1].data.datamem, sp [0].data.datamem)) \
4642 sp [-1].data.i = noorder; \
4643 else \
4644 sp [-1].data.i = sp [-1].data.datamem op sp [0].data.datamem; \
4645 ++ip;
4646
4647 MINT_IN_CASE(MINT_CEQ_I4)
4648 RELOP(i, ==);
4649 MINT_IN_BREAK;
4650 MINT_IN_CASE(MINT_CEQ0_I4)
4651 sp [-1].data.i = (sp [-1].data.i == 0);
4652 ++ip;
4653 MINT_IN_BREAK;
4654 MINT_IN_CASE(MINT_CEQ_I8)
4655 RELOP(l, ==);
4656 MINT_IN_BREAK;
4657 MINT_IN_CASE(MINT_CEQ_R8)
4658 RELOP_FP(f, ==, 0);
4659 MINT_IN_BREAK;
4660 MINT_IN_CASE(MINT_CNE_I4)
4661 RELOP(i, !=);
4662 MINT_IN_BREAK;
4663 MINT_IN_CASE(MINT_CNE_I8)
4664 RELOP(l, !=);
4665 MINT_IN_BREAK;
4666 MINT_IN_CASE(MINT_CNE_R8)
4667 RELOP_FP(f, !=, 0);
4668 MINT_IN_BREAK;
4669 MINT_IN_CASE(MINT_CGT_I4)
4670 RELOP(i, >);
4671 MINT_IN_BREAK;
4672 MINT_IN_CASE(MINT_CGT_I8)
4673 RELOP(l, >);
4674 MINT_IN_BREAK;
4675 MINT_IN_CASE(MINT_CGT_R8)
4676 RELOP_FP(f, >, 0);
4677 MINT_IN_BREAK;
4678 MINT_IN_CASE(MINT_CGE_I4)
4679 RELOP(i, >=);
4680 MINT_IN_BREAK;
4681 MINT_IN_CASE(MINT_CGE_I8)
4682 RELOP(l, >=);
4683 MINT_IN_BREAK;
4684 MINT_IN_CASE(MINT_CGE_R8)
4685 RELOP_FP(f, >=, 0);
4686 MINT_IN_BREAK;
4687
4688 #define RELOP_CAST(datamem, op, type) \
4689 --sp; \
4690 sp [-1].data.i = (type)sp [-1].data.datamem op (type)sp [0].data.datamem; \
4691 ++ip;
4692
4693 MINT_IN_CASE(MINT_CGE_UN_I4)
4694 RELOP_CAST(l, >=, guint32);
4695 MINT_IN_BREAK;
4696 MINT_IN_CASE(MINT_CGE_UN_I8)
4697 RELOP_CAST(l, >=, guint64);
4698 MINT_IN_BREAK;
4699
4700 MINT_IN_CASE(MINT_CGT_UN_I4)
4701 RELOP_CAST(i, >, guint32);
4702 MINT_IN_BREAK;
4703 MINT_IN_CASE(MINT_CGT_UN_I8)
4704 RELOP_CAST(l, >, guint64);
4705 MINT_IN_BREAK;
4706 MINT_IN_CASE(MINT_CGT_UN_R8)
4707 RELOP_FP(f, >, 1);
4708 MINT_IN_BREAK;
4709 MINT_IN_CASE(MINT_CLT_I4)
4710 RELOP(i, <);
4711 MINT_IN_BREAK;
4712 MINT_IN_CASE(MINT_CLT_I8)
4713 RELOP(l, <);
4714 MINT_IN_BREAK;
4715 MINT_IN_CASE(MINT_CLT_R8)
4716 RELOP_FP(f, <, 0);
4717 MINT_IN_BREAK;
4718 MINT_IN_CASE(MINT_CLT_UN_I4)
4719 RELOP_CAST(i, <, guint32);
4720 MINT_IN_BREAK;
4721 MINT_IN_CASE(MINT_CLT_UN_I8)
4722 RELOP_CAST(l, <, guint64);
4723 MINT_IN_BREAK;
4724 MINT_IN_CASE(MINT_CLT_UN_R8)
4725 RELOP_FP(f, <, 1);
4726 MINT_IN_BREAK;
4727 MINT_IN_CASE(MINT_CLE_I4)
4728 RELOP(i, <=);
4729 MINT_IN_BREAK;
4730 MINT_IN_CASE(MINT_CLE_I8)
4731 RELOP(l, <=);
4732 MINT_IN_BREAK;
4733 MINT_IN_CASE(MINT_CLE_UN_I4)
4734 RELOP_CAST(l, <=, guint32);
4735 MINT_IN_BREAK;
4736 MINT_IN_CASE(MINT_CLE_UN_I8)
4737 RELOP_CAST(l, <=, guint64);
4738 MINT_IN_BREAK;
4739 MINT_IN_CASE(MINT_CLE_R8)
4740 RELOP_FP(f, <=, 0);
4741 MINT_IN_BREAK;
4742
4743 #undef RELOP
4744 #undef RELOP_FP
4745 #undef RELOP_CAST
4746
4747 MINT_IN_CASE(MINT_LDFTN) {
4748 sp->data.p = rtm->data_items [* (guint16 *)(ip + 1)];
4749 ++sp;
4750 ip += 2;
4751 MINT_IN_BREAK;
4752 }
4753 MINT_IN_CASE(MINT_LDVIRTFTN) {
4754 InterpMethod *m = rtm->data_items [* (guint16 *)(ip + 1)];
4755 ip += 2;
4756 --sp;
4757 if (!sp->data.p)
4758 THROW_EX (mono_get_exception_null_reference (), ip - 2);
4759
4760 sp->data.p = get_virtual_method (m, sp->data.p);
4761 ++sp;
4762 MINT_IN_BREAK;
4763 }
4764
4765 #define LDARG(datamem, argtype) \
4766 sp->data.datamem = * (argtype *)(frame->args + * (guint16 *)(ip + 1)); \
4767 ip += 2; \
4768 ++sp;
4769
4770 MINT_IN_CASE(MINT_LDARG_I1) LDARG(i, gint8); MINT_IN_BREAK;
4771 MINT_IN_CASE(MINT_LDARG_U1) LDARG(i, guint8); MINT_IN_BREAK;
4772 MINT_IN_CASE(MINT_LDARG_I2) LDARG(i, gint16); MINT_IN_BREAK;
4773 MINT_IN_CASE(MINT_LDARG_U2) LDARG(i, guint16); MINT_IN_BREAK;
4774 MINT_IN_CASE(MINT_LDARG_I4) LDARG(i, gint32); MINT_IN_BREAK;
4775 MINT_IN_CASE(MINT_LDARG_I8) LDARG(l, gint64); MINT_IN_BREAK;
4776 MINT_IN_CASE(MINT_LDARG_R4) LDARG(f, float); MINT_IN_BREAK;
4777 MINT_IN_CASE(MINT_LDARG_R8) LDARG(f, double); MINT_IN_BREAK;
4778 MINT_IN_CASE(MINT_LDARG_O) LDARG(p, gpointer); MINT_IN_BREAK;
4779 MINT_IN_CASE(MINT_LDARG_P) LDARG(p, gpointer); MINT_IN_BREAK;
4780
4781 MINT_IN_CASE(MINT_LDARG_VT)
4782 sp->data.p = vt_sp;
4783 i32 = READ32(ip + 2);
4784 memcpy(sp->data.p, frame->args + * (guint16 *)(ip + 1), i32);
4785 vt_sp += (i32 + 7) & ~7;
4786 ip += 4;
4787 ++sp;
4788 MINT_IN_BREAK;
4789
4790 #define STARG(datamem, argtype) \
4791 --sp; \
4792 * (argtype *)(frame->args + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4793 ip += 2; \
4794
4795 MINT_IN_CASE(MINT_STARG_I1) STARG(i, gint8); MINT_IN_BREAK;
4796 MINT_IN_CASE(MINT_STARG_U1) STARG(i, guint8); MINT_IN_BREAK;
4797 MINT_IN_CASE(MINT_STARG_I2) STARG(i, gint16); MINT_IN_BREAK;
4798 MINT_IN_CASE(MINT_STARG_U2) STARG(i, guint16); MINT_IN_BREAK;
4799 MINT_IN_CASE(MINT_STARG_I4) STARG(i, gint32); MINT_IN_BREAK;
4800 MINT_IN_CASE(MINT_STARG_I8) STARG(l, gint64); MINT_IN_BREAK;
4801 MINT_IN_CASE(MINT_STARG_R4) STARG(f, float); MINT_IN_BREAK;
4802 MINT_IN_CASE(MINT_STARG_R8) STARG(f, double); MINT_IN_BREAK;
4803 MINT_IN_CASE(MINT_STARG_O) STARG(p, gpointer); MINT_IN_BREAK;
4804 MINT_IN_CASE(MINT_STARG_P) STARG(p, gpointer); MINT_IN_BREAK;
4805
4806 MINT_IN_CASE(MINT_STARG_VT)
4807 i32 = READ32(ip + 2);
4808 --sp;
4809 memcpy(frame->args + * (guint16 *)(ip + 1), sp->data.p, i32);
4810 vt_sp -= (i32 + 7) & ~7;
4811 ip += 4;
4812 MINT_IN_BREAK;
4813
4814 #define STINARG(datamem, argtype) \
4815 do { \
4816 int n = * (guint16 *)(ip + 1); \
4817 * (argtype *)(frame->args + rtm->arg_offsets [n]) = frame->stack_args [n].data.datamem; \
4818 ip += 2; \
4819 } while (0)
4820
4821 MINT_IN_CASE(MINT_STINARG_I1) STINARG(i, gint8); MINT_IN_BREAK;
4822 MINT_IN_CASE(MINT_STINARG_U1) STINARG(i, guint8); MINT_IN_BREAK;
4823 MINT_IN_CASE(MINT_STINARG_I2) STINARG(i, gint16); MINT_IN_BREAK;
4824 MINT_IN_CASE(MINT_STINARG_U2) STINARG(i, guint16); MINT_IN_BREAK;
4825 MINT_IN_CASE(MINT_STINARG_I4) STINARG(i, gint32); MINT_IN_BREAK;
4826 MINT_IN_CASE(MINT_STINARG_I8) STINARG(l, gint64); MINT_IN_BREAK;
4827 MINT_IN_CASE(MINT_STINARG_R4) STINARG(f, float); MINT_IN_BREAK;
4828 MINT_IN_CASE(MINT_STINARG_R8) STINARG(f, double); MINT_IN_BREAK;
4829 MINT_IN_CASE(MINT_STINARG_O) STINARG(p, gpointer); MINT_IN_BREAK;
4830 MINT_IN_CASE(MINT_STINARG_P) STINARG(p, gpointer); MINT_IN_BREAK;
4831
4832 MINT_IN_CASE(MINT_STINARG_VT) {
4833 int n = * (guint16 *)(ip + 1);
4834 i32 = READ32(ip + 2);
4835 memcpy (frame->args + rtm->arg_offsets [n], frame->stack_args [n].data.p, i32);
4836 ip += 4;
4837 MINT_IN_BREAK;
4838 }
4839
4840 MINT_IN_CASE(MINT_PROF_ENTER) {
4841 ip += 1;
4842
4843 if (MONO_PROFILER_ENABLED (method_enter)) {
4844 MonoProfilerCallContext *prof_ctx = NULL;
4845
4846 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
4847 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
4848 prof_ctx->interp_frame = frame;
4849 prof_ctx->method = frame->imethod->method;
4850 }
4851
4852 MONO_PROFILER_RAISE (method_enter, (frame->imethod->method, prof_ctx));
4853
4854 g_free (prof_ctx);
4855 }
4856
4857 MINT_IN_BREAK;
4858 }
4859
4860 MINT_IN_CASE(MINT_LDARGA)
4861 sp->data.p = frame->args + * (guint16 *)(ip + 1);
4862 ip += 2;
4863 ++sp;
4864 MINT_IN_BREAK;
4865
4866 #define LDLOC(datamem, argtype) \
4867 sp->data.datamem = * (argtype *)(locals + * (guint16 *)(ip + 1)); \
4868 ip += 2; \
4869 ++sp;
4870
4871 MINT_IN_CASE(MINT_LDLOC_I1) LDLOC(i, gint8); MINT_IN_BREAK;
4872 MINT_IN_CASE(MINT_LDLOC_U1) LDLOC(i, guint8); MINT_IN_BREAK;
4873 MINT_IN_CASE(MINT_LDLOC_I2) LDLOC(i, gint16); MINT_IN_BREAK;
4874 MINT_IN_CASE(MINT_LDLOC_U2) LDLOC(i, guint16); MINT_IN_BREAK;
4875 MINT_IN_CASE(MINT_LDLOC_I4) LDLOC(i, gint32); MINT_IN_BREAK;
4876 MINT_IN_CASE(MINT_LDLOC_I8) LDLOC(l, gint64); MINT_IN_BREAK;
4877 MINT_IN_CASE(MINT_LDLOC_R4) LDLOC(f, float); MINT_IN_BREAK;
4878 MINT_IN_CASE(MINT_LDLOC_R8) LDLOC(f, double); MINT_IN_BREAK;
4879 MINT_IN_CASE(MINT_LDLOC_O) LDLOC(p, gpointer); MINT_IN_BREAK;
4880 MINT_IN_CASE(MINT_LDLOC_P) LDLOC(p, gpointer); MINT_IN_BREAK;
4881
4882 MINT_IN_CASE(MINT_LDLOC_VT)
4883 sp->data.p = vt_sp;
4884 i32 = READ32(ip + 2);
4885 memcpy(sp->data.p, locals + * (guint16 *)(ip + 1), i32);
4886 vt_sp += (i32 + 7) & ~7;
4887 ip += 4;
4888 ++sp;
4889 MINT_IN_BREAK;
4890
4891 MINT_IN_CASE(MINT_LDLOCA_S)
4892 sp->data.p = locals + * (guint16 *)(ip + 1);
4893 ip += 2;
4894 ++sp;
4895 MINT_IN_BREAK;
4896
4897 #define STLOC(datamem, argtype) \
4898 --sp; \
4899 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp->data.datamem; \
4900 ip += 2;
4901
4902 MINT_IN_CASE(MINT_STLOC_I1) STLOC(i, gint8); MINT_IN_BREAK;
4903 MINT_IN_CASE(MINT_STLOC_U1) STLOC(i, guint8); MINT_IN_BREAK;
4904 MINT_IN_CASE(MINT_STLOC_I2) STLOC(i, gint16); MINT_IN_BREAK;
4905 MINT_IN_CASE(MINT_STLOC_U2) STLOC(i, guint16); MINT_IN_BREAK;
4906 MINT_IN_CASE(MINT_STLOC_I4) STLOC(i, gint32); MINT_IN_BREAK;
4907 MINT_IN_CASE(MINT_STLOC_I8) STLOC(l, gint64); MINT_IN_BREAK;
4908 MINT_IN_CASE(MINT_STLOC_R4) STLOC(f, float); MINT_IN_BREAK;
4909 MINT_IN_CASE(MINT_STLOC_R8) STLOC(f, double); MINT_IN_BREAK;
4910 MINT_IN_CASE(MINT_STLOC_O) STLOC(p, gpointer); MINT_IN_BREAK;
4911 MINT_IN_CASE(MINT_STLOC_P) STLOC(p, gpointer); MINT_IN_BREAK;
4912
4913 #define STLOC_NP(datamem, argtype) \
4914 * (argtype *)(locals + * (guint16 *)(ip + 1)) = sp [-1].data.datamem; \
4915 ip += 2;
4916
4917 MINT_IN_CASE(MINT_STLOC_NP_I4) STLOC_NP(i, gint32); MINT_IN_BREAK;
4918 MINT_IN_CASE(MINT_STLOC_NP_O) STLOC_NP(p, gpointer); MINT_IN_BREAK;
4919
4920 MINT_IN_CASE(MINT_STLOC_VT)
4921 i32 = READ32(ip + 2);
4922 --sp;
4923 memcpy(locals + * (guint16 *)(ip + 1), sp->data.p, i32);
4924 vt_sp -= (i32 + 7) & ~7;
4925 ip += 4;
4926 MINT_IN_BREAK;
4927
4928 MINT_IN_CASE(MINT_LOCALLOC) {
4929 if (sp != frame->stack + 1) /*FIX?*/
4930 THROW_EX (mono_get_exception_execution_engine (NULL), ip);
4931
4932 int len = sp [-1].data.i;
4933 sp [-1].data.p = alloca (len);
4934
4935 if (frame->imethod->init_locals)
4936 memset (sp [-1].data.p, 0, len);
4937 ++ip;
4938 MINT_IN_BREAK;
4939 }
4940 MINT_IN_CASE(MINT_ENDFILTER)
4941 /* top of stack is result of filter */
4942 frame->retval = &sp [-1];
4943 goto exit_frame;
4944 MINT_IN_CASE(MINT_INITOBJ)
4945 --sp;
4946 memset (sp->data.vt, 0, READ32(ip + 1));
4947 ip += 3;
4948 MINT_IN_BREAK;
4949 MINT_IN_CASE(MINT_CPBLK)
4950 sp -= 3;
4951 if (!sp [0].data.p || !sp [1].data.p)
4952 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4953 ++ip;
4954 /* FIXME: value and size may be int64... */
4955 memcpy (sp [0].data.p, sp [1].data.p, sp [2].data.i);
4956 MINT_IN_BREAK;
4957 #if 0
4958 MINT_IN_CASE(MINT_CONSTRAINED_) {
4959 guint32 token;
4960 /* FIXME: implement */
4961 ++ip;
4962 token = READ32 (ip);
4963 ip += 2;
4964 MINT_IN_BREAK;
4965 }
4966 #endif
4967 MINT_IN_CASE(MINT_INITBLK)
4968 sp -= 3;
4969 if (!sp [0].data.p)
4970 THROW_EX (mono_get_exception_null_reference(), ip - 1);
4971 ++ip;
4972 /* FIXME: value and size may be int64... */
4973 memset (sp [0].data.p, sp [1].data.i, sp [2].data.i);
4974 MINT_IN_BREAK;
4975 #if 0
4976 MINT_IN_CASE(MINT_NO_)
4977 /* FIXME: implement */
4978 ip += 2;
4979 MINT_IN_BREAK;
4980 #endif
4981 MINT_IN_CASE(MINT_RETHROW) {
4982 /*
4983 * need to clarify what this should actually do:
4984 * start the search from the last found handler in
4985 * this method or continue in the caller or what.
4986 * Also, do we need to run finally/fault handlers after a retrow?
4987 * Well, this implementation will follow the usual search
4988 * for an handler, considering the current ip as throw spot.
4989 * We need to NULL frame->ex_handler for the later code to
4990 * actually run the new found handler.
4991 */
4992 int exvar_offset = *(guint16*)(ip + 1);
4993 frame->ex_handler = NULL;
4994 THROW_EX_GENERAL (*(MonoException**)(frame->locals + exvar_offset), ip - 1, TRUE);
4995 MINT_IN_BREAK;
4996 }
4997 MINT_IN_DEFAULT
4998 g_print ("Unimplemented opcode: %04x %s at 0x%x\n", *ip, mono_interp_opname[*ip], ip-rtm->code);
4999 THROW_EX (mono_get_exception_execution_engine ("Unimplemented opcode"), ip);
5000 }
5001 }
5002
5003 g_assert_not_reached ();
5004 handle_finally:
5005 {
5006 int i;
5007 guint32 ip_offset;
5008 MonoExceptionClause *clause;
5009 GSList *old_list = finally_ips;
5010 MonoMethod *method = frame->imethod->method;
5011
5012 #if DEBUG_INTERP
5013 if (tracing)
5014 g_print ("* Handle finally IL_%04x\n", endfinally_ip == NULL ? 0 : endfinally_ip - rtm->code);
5015 #endif
5016 if (rtm == NULL || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
5017 || (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME))) {
5018 goto exit_frame;
5019 }
5020 ip_offset = frame->ip - rtm->code;
5021
5022 if (endfinally_ip != NULL)
5023 finally_ips = g_slist_prepend(finally_ips, (void *)endfinally_ip);
5024 for (i = 0; i < rtm->num_clauses; ++i)
5025 if (frame->ex_handler == &rtm->clauses [i])
5026 break;
5027
5028 while (i > 0) {
5029 --i;
5030 clause = &rtm->clauses [i];
5031 if (MONO_OFFSET_IN_CLAUSE (clause, ip_offset) && (endfinally_ip == NULL || !(MONO_OFFSET_IN_CLAUSE (clause, endfinally_ip - rtm->code)))) {
5032 if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
5033 ip = rtm->code + clause->handler_offset;
5034 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5035 #if DEBUG_INTERP
5036 if (tracing)
5037 g_print ("* Found finally at IL_%04x with exception: %s\n", clause->handler_offset, frame->ex? "yes": "no");
5038 #endif
5039 }
5040 }
5041 }
5042
5043 endfinally_ip = NULL;
5044
5045 if (old_list != finally_ips && finally_ips) {
5046 ip = finally_ips->data;
5047 finally_ips = g_slist_remove (finally_ips, ip);
5048 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5049 vt_sp = (unsigned char *) sp + rtm->stack_size;
5050 goto main_loop;
5051 }
5052
5053 /*
5054 * If an exception is set, we need to execute the fault handler, too,
5055 * otherwise, we continue normally.
5056 */
5057 if (frame->ex)
5058 goto handle_fault;
5059 ves_abort();
5060 }
5061 handle_fault:
5062 {
5063 int i;
5064 guint32 ip_offset;
5065 MonoExceptionClause *clause;
5066 GSList *old_list = finally_ips;
5067
5068 #if DEBUG_INTERP
5069 if (tracing)
5070 g_print ("* Handle fault\n");
5071 #endif
5072 ip_offset = frame->ip - rtm->code;
5073
5074 for (i = 0; i < rtm->num_clauses; ++i) {
5075 clause = &rtm->clauses [i];
5076 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT && MONO_OFFSET_IN_CLAUSE (clause, ip_offset)) {
5077 ip = rtm->code + clause->handler_offset;
5078 finally_ips = g_slist_prepend (finally_ips, (gpointer) ip);
5079 #if DEBUG_INTERP
5080 if (tracing)
5081 g_print ("* Executing handler at IL_%04x\n", clause->handler_offset);
5082 #endif
5083 }
5084 }
5085
5086 if (old_list != finally_ips && finally_ips) {
5087 ip = finally_ips->data;
5088 finally_ips = g_slist_remove (finally_ips, ip);
5089 sp = frame->stack; /* spec says stack should be empty at endfinally so it should be at the start too */
5090 vt_sp = (unsigned char *) sp + rtm->stack_size;
5091 goto main_loop;
5092 }
5093 }
5094 handle_catch:
5095 {
5096 /*
5097 * If the handler for the exception was found in this method, we jump
5098 * to it right away, otherwise we return and let the caller run
5099 * the finally, fault and catch blocks.
5100 * This same code should be present in the endfault opcode, but it
5101 * is corrently not assigned in the ECMA specs: LAMESPEC.
5102 */
5103 if (frame->ex_handler) {
5104 #if DEBUG_INTERP
5105 if (tracing)
5106 g_print ("* Executing handler at IL_%04x\n", frame->ex_handler->handler_offset);
5107 #endif
5108 ip = rtm->code + frame->ex_handler->handler_offset;
5109 sp = frame->stack;
5110 vt_sp = (unsigned char *) sp + rtm->stack_size;
5111 sp->data.p = frame->ex;
5112 ++sp;
5113 goto main_loop;
5114 }
5115 goto check_lmf;
5116 }
5117
5118 check_lmf:
5119 {
5120 /* make sure we don't miss to pop a LMF */
5121 MonoLMF *lmf= mono_get_lmf ();
5122 if (lmf && (gsize) lmf->previous_lmf & 2) {
5123 MonoLMFExt *ext = (MonoLMFExt *) lmf;
5124 if (ext->interp_exit && ext->interp_exit_data == frame->parent)
5125 interp_pop_lmf (ext);
5126 }
5127 }
5128
5129 exit_frame:
5130
5131 if (base_frame)
5132 memcpy (base_frame->args, frame->args, rtm->alloca_size);
5133
5134 if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
5135 frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
5136 MonoProfilerCallContext *prof_ctx = NULL;
5137
5138 if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
5139 prof_ctx = g_new0 (MonoProfilerCallContext, 1);
5140 prof_ctx->interp_frame = frame;
5141 prof_ctx->method = frame->imethod->method;
5142
5143 MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
5144
5145 switch (rtype->type) {
5146 case MONO_TYPE_VOID:
5147 break;
5148 case MONO_TYPE_VALUETYPE:
5149 prof_ctx->return_value = frame->retval->data.p;
5150 break;
5151 default:
5152 prof_ctx->return_value = frame->retval;
5153 break;
5154 }
5155 }
5156
5157 MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
5158
5159 g_free (prof_ctx);
5160 } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
5161 MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
5162
5163 DEBUG_LEAVE ();
5164 }
5165
5166 static void
interp_exec_method(InterpFrame * frame,ThreadContext * context)5167 interp_exec_method (InterpFrame *frame, ThreadContext *context)
5168 {
5169 interp_exec_method_full (frame, context, NULL, NULL, -1, NULL);
5170 }
5171
5172 void
mono_interp_parse_options(const char * options)5173 mono_interp_parse_options (const char *options)
5174 {
5175 char **args, **ptr;
5176
5177 args = g_strsplit (options, ",", -1);
5178 for (ptr = args; ptr && *ptr; ptr ++) {
5179 char *arg = *ptr;
5180
5181 if (strncmp (arg, "jit=", 4) == 0)
5182 jit_classes = g_slist_prepend (jit_classes, arg + 4);
5183 }
5184 }
5185
5186 typedef int (*TestMethod) (void);
5187
5188 /*
5189 * interp_set_resume_state:
5190 *
5191 * Set the state the interpeter will continue to execute from after execution returns to the interpreter.
5192 */
5193 static void
interp_set_resume_state(MonoJitTlsData * jit_tls,MonoException * ex,MonoJitExceptionInfo * ei,MonoInterpFrameHandle interp_frame,gpointer handler_ip)5194 interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
5195 {
5196 ThreadContext *context;
5197
5198 g_assert (jit_tls);
5199 context = jit_tls->interp_context;
5200 g_assert (context);
5201
5202 context->has_resume_state = TRUE;
5203 context->handler_frame = interp_frame;
5204 /* This is on the stack, so it doesn't need a wbarrier */
5205 context->handler_frame->ex = ex;
5206 /* Ditto */
5207 if (ei)
5208 *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex;
5209 context->handler_ip = handler_ip;
5210 }
5211
5212 /*
5213 * interp_run_finally:
5214 *
5215 * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by
5216 * frame->interp_frame.
5217 * Return TRUE if the finally clause threw an exception.
5218 */
5219 static gboolean
interp_run_finally(StackFrameInfo * frame,int clause_index,gpointer handler_ip)5220 interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip)
5221 {
5222 InterpFrame *iframe = frame->interp_frame;
5223 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5224
5225 interp_exec_method_full (iframe, context, handler_ip, NULL, clause_index, NULL);
5226 if (context->has_resume_state)
5227 return TRUE;
5228 else
5229 return FALSE;
5230 }
5231
5232 /*
5233 * interp_run_filter:
5234 *
5235 * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by
5236 * frame->interp_frame.
5237 */
5238 static gboolean
interp_run_filter(StackFrameInfo * frame,MonoException * ex,int clause_index,gpointer handler_ip)5239 interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip)
5240 {
5241 InterpFrame *iframe = frame->interp_frame;
5242 ThreadContext *context = mono_native_tls_get_value (thread_context_id);
5243 InterpFrame child_frame;
5244 stackval retval;
5245
5246 /*
5247 * Have to run the clause in a new frame which is a copy of IFRAME, since
5248 * during debugging, there are two copies of the frame on the stack.
5249 */
5250 memset (&child_frame, 0, sizeof (InterpFrame));
5251 child_frame.imethod = iframe->imethod;
5252 child_frame.retval = &retval;
5253 child_frame.parent = iframe;
5254
5255 interp_exec_method_full (&child_frame, context, handler_ip, ex, clause_index, iframe);
5256 /* ENDFILTER stores the result into child_frame->retval */
5257 return child_frame.retval->data.i ? TRUE : FALSE;
5258 }
5259
5260 typedef struct {
5261 InterpFrame *current;
5262 } StackIter;
5263
5264 /*
5265 * interp_frame_iter_init:
5266 *
5267 * Initialize an iterator for iterating through interpreted frames.
5268 */
5269 static void
interp_frame_iter_init(MonoInterpStackIter * iter,gpointer interp_exit_data)5270 interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data)
5271 {
5272 StackIter *stack_iter = (StackIter*)iter;
5273
5274 stack_iter->current = (InterpFrame*)interp_exit_data;
5275 }
5276
5277 /*
5278 * interp_frame_iter_next:
5279 *
5280 * Fill out FRAME with date for the next interpreter frame.
5281 */
5282 static gboolean
interp_frame_iter_next(MonoInterpStackIter * iter,StackFrameInfo * frame)5283 interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
5284 {
5285 StackIter *stack_iter = (StackIter*)iter;
5286 InterpFrame *iframe = stack_iter->current;
5287
5288 memset (frame, 0, sizeof (StackFrameInfo));
5289 /* pinvoke frames doesn't have imethod set */
5290 while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo))
5291 iframe = iframe->parent;
5292 if (!iframe)
5293 return FALSE;
5294
5295 frame->type = FRAME_TYPE_INTERP;
5296 frame->domain = iframe->domain;
5297 frame->interp_frame = iframe;
5298 frame->method = iframe->imethod->method;
5299 frame->actual_method = frame->method;
5300 /* This is the offset in the interpreter IR */
5301 frame->native_offset = (guint8*)iframe->ip - (guint8*)iframe->imethod->code;
5302 frame->ji = iframe->imethod->jinfo;
5303
5304 stack_iter->current = iframe->parent;
5305
5306 return TRUE;
5307 }
5308
5309 static MonoJitInfo*
interp_find_jit_info(MonoDomain * domain,MonoMethod * method)5310 interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
5311 {
5312 InterpMethod* rtm;
5313
5314 rtm = lookup_imethod (domain, method);
5315 if (rtm)
5316 return rtm->jinfo;
5317 else
5318 return NULL;
5319 }
5320
5321 static void
interp_set_breakpoint(MonoJitInfo * jinfo,gpointer ip)5322 interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5323 {
5324 guint16 *code = (guint16*)ip;
5325 g_assert (*code == MINT_SDB_SEQ_POINT);
5326 *code = MINT_SDB_BREAKPOINT;
5327 }
5328
5329 static void
interp_clear_breakpoint(MonoJitInfo * jinfo,gpointer ip)5330 interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
5331 {
5332 guint16 *code = (guint16*)ip;
5333 g_assert (*code == MINT_SDB_BREAKPOINT);
5334 *code = MINT_SDB_SEQ_POINT;
5335 }
5336
5337 static MonoJitInfo*
interp_frame_get_jit_info(MonoInterpFrameHandle frame)5338 interp_frame_get_jit_info (MonoInterpFrameHandle frame)
5339 {
5340 InterpFrame *iframe = (InterpFrame*)frame;
5341
5342 g_assert (iframe->imethod);
5343 return iframe->imethod->jinfo;
5344 }
5345
5346 static gpointer
interp_frame_get_ip(MonoInterpFrameHandle frame)5347 interp_frame_get_ip (MonoInterpFrameHandle frame)
5348 {
5349 InterpFrame *iframe = (InterpFrame*)frame;
5350
5351 g_assert (iframe->imethod);
5352 return (gpointer)iframe->ip;
5353 }
5354
5355 static gpointer
interp_frame_get_arg(MonoInterpFrameHandle frame,int pos)5356 interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
5357 {
5358 InterpFrame *iframe = (InterpFrame*)frame;
5359
5360 g_assert (iframe->imethod);
5361
5362 int arg_offset = iframe->imethod->arg_offsets [pos + (iframe->imethod->hasthis ? 1 : 0)];
5363
5364 return iframe->args + arg_offset;
5365 }
5366
5367 static gpointer
interp_frame_get_local(MonoInterpFrameHandle frame,int pos)5368 interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
5369 {
5370 InterpFrame *iframe = (InterpFrame*)frame;
5371
5372 g_assert (iframe->imethod);
5373
5374 return iframe->locals + iframe->imethod->local_offsets [pos];
5375 }
5376
5377 static gpointer
interp_frame_get_this(MonoInterpFrameHandle frame)5378 interp_frame_get_this (MonoInterpFrameHandle frame)
5379 {
5380 InterpFrame *iframe = (InterpFrame*)frame;
5381
5382 g_assert (iframe->imethod);
5383 g_assert (iframe->imethod->hasthis);
5384
5385 int arg_offset = iframe->imethod->arg_offsets [0];
5386
5387 return iframe->args + arg_offset;
5388 }
5389
5390 static MonoInterpFrameHandle
interp_frame_get_parent(MonoInterpFrameHandle frame)5391 interp_frame_get_parent (MonoInterpFrameHandle frame)
5392 {
5393 InterpFrame *iframe = (InterpFrame*)frame;
5394
5395 return iframe->parent;
5396 }
5397
5398 static void
interp_start_single_stepping(void)5399 interp_start_single_stepping (void)
5400 {
5401 ss_enabled = TRUE;
5402 }
5403
5404 static void
interp_stop_single_stepping(void)5405 interp_stop_single_stepping (void)
5406 {
5407 ss_enabled = FALSE;
5408 }
5409
5410 void
mono_interp_init()5411 mono_interp_init ()
5412 {
5413 mono_native_tls_alloc (&thread_context_id, NULL);
5414 set_context (NULL);
5415
5416 mono_interp_transform_init ();
5417
5418 MonoInterpCallbacks c;
5419 c.create_method_pointer = interp_create_method_pointer;
5420 c.runtime_invoke = interp_runtime_invoke;
5421 c.init_delegate = interp_init_delegate;
5422 #ifndef DISABLE_REMOTING
5423 c.get_remoting_invoke = interp_get_remoting_invoke;
5424 #endif
5425 c.create_trampoline = interp_create_trampoline;
5426 c.walk_stack_with_ctx = interp_walk_stack_with_ctx;
5427 c.set_resume_state = interp_set_resume_state;
5428 c.run_finally = interp_run_finally;
5429 c.run_filter = interp_run_filter;
5430 c.frame_iter_init = interp_frame_iter_init;
5431 c.frame_iter_next = interp_frame_iter_next;
5432 c.find_jit_info = interp_find_jit_info;
5433 c.set_breakpoint = interp_set_breakpoint;
5434 c.clear_breakpoint = interp_clear_breakpoint;
5435 c.frame_get_jit_info = interp_frame_get_jit_info;
5436 c.frame_get_ip = interp_frame_get_ip;
5437 c.frame_get_arg = interp_frame_get_arg;
5438 c.frame_get_local = interp_frame_get_local;
5439 c.frame_get_this = interp_frame_get_this;
5440 c.frame_get_parent = interp_frame_get_parent;
5441 c.start_single_stepping = interp_start_single_stepping;
5442 c.stop_single_stepping = interp_stop_single_stepping;
5443 mini_install_interp_callbacks (&c);
5444 }
5445