Tue Jul 24 16:51:09 CEST 2001 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / interpreter / interp.c
1 /*
2  * PLEASE NOTE: This is a research prototype.
3  *
4  *
5  * interp.c: Interpreter for CIL byte codes
6  *
7  * Authors:
8  *   Paolo Molaro (lupus@ximian.com)
9  *   Miguel de Icaza (miguel@ximian.com)
10  *
11  * (C) 2001 Ximian, Inc.
12  */
13 #include <config.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <glib.h>
17
18 #ifdef HAVE_ALLOCA_H
19 #   include <alloca.h>
20 #else
21 #   ifdef __CYGWIN__
22 #      define alloca __builtin_alloca
23 #   endif
24 #endif
25
26 #include "interp.h"
27 /* trim excessive headers */
28 #include <mono/metadata/image.h>
29 #include <mono/metadata/assembly.h>
30 #include <mono/metadata/cil-coff.h>
31 #include <mono/metadata/endian.h>
32 #include <mono/metadata/tabledefs.h>
33 #include <mono/metadata/blob.h>
34 #include <mono/metadata/tokentype.h>
35 #include <mono/cli/cli.h>
36 #include "hacks.h"
37
38 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
39         a = i,
40
41 enum {
42 #include "mono/cil/opcode.def"
43         LAST = 0xff
44 };
45 #undef OPDEF
46
47 /* this needs to be metadata,token indexed, not only token */
48 static GHashTable * method_cache = 0;
49
50 /* FIXME: check in configure */
51 typedef gint32 nati_t;
52
53 #define GET_NATI(sp) ((guint32)(sp).data.i)
54
55 static int count = 0;
56
57 #define CSIZE(x) (sizeof (x) / 4)
58
59 static void
60 ves_real_abort (int line, MonoImage *image, MonoMethod *mh,
61                 const unsigned char *ip, stackval *stack, stackval *sp)
62 {
63         cli_image_info_t *iinfo = image->image_info;
64         metadata_t *m = &iinfo->cli_metadata;
65         const char *name = mono_metadata_string_heap (m, mh->name_idx);
66                 
67         fprintf (stderr, "Execution aborted in method: %s\n", name);
68         fprintf (stderr, "Line=%d IP=0x%04x, Aborted execution\n", line,
69                  ip-(unsigned char *)mh->header->code);
70         g_print ("0x%04x %02x\n",
71                  ip-(unsigned char*)mh->header->code, *ip);
72         if (sp > stack)
73                 printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type, sp[-1].data.i, sp[-1].data.f);
74         exit (1);
75 }
76 #define ves_abort() ves_real_abort(__LINE__, image, mh, ip, stack, sp)
77
78 /*
79  * newobj:
80  * @image: image where the object is being referenced
81  * @token: method token to invoke
82  *
83  * This routine creates a new object based on the class where the
84  * constructor lives.x
85  */
86 static MonoObject *
87 newobj (MonoImage *image, guint32 token)
88 {
89         cli_image_info_t *iinfo = image->image_info;
90         metadata_t *m = &iinfo->cli_metadata;
91         
92         switch (mono_metadata_token_code (token)){
93         case TOKEN_TYPE_METHOD_DEF:
94                 g_error ("TOKEN_TYPE_METHOD_DEF not supported in newobj yet");
95                 break;
96                 
97         case TOKEN_TYPE_MEMBER_REF: {
98                 guint32 member_cols [3];
99                 guint32 mpr_token, table, idx;
100                 
101                 mono_metadata_decode_row (
102                         &m->tables [META_TABLE_MEMBERREF],
103                         mono_metadata_token_index (token) - 1,
104                         member_cols, CSIZE (member_cols));
105                 mpr_token = member_cols [0];
106                 table = mpr_token & 7;
107                 idx = mpr_token >> 3;
108                 
109                 switch (table){
110                 case 0: /* TypeDef */
111                         return mono_object_new (image, TOKEN_TYPE_TYPE_DEF | idx);
112                         
113                 case 1: /* TypeRef */
114                         return mono_object_new (image, TOKEN_TYPE_TYPE_REF | idx);
115                         
116                 case 2: /* ModuleRef */
117                         g_error ("Unhandled: ModuleRef");
118                         
119                 case 3: /* MethodDef */
120                         g_error ("Unhandled: MethodDef");
121                         
122                 case 4: /* TypeSpec */
123                         g_error ("Unhandled: TypeSepc");
124                 }
125                 break;
126         }
127         }
128
129         /*
130          * Failure
131          */
132         return NULL;
133 }
134
135 /*
136  * Need to optimize ALU ops when natural int == int32 
137  *
138  * Need to design how exceptions are supposed to work...
139  *
140  * IDEA: if we maintain a stack of ip, sp to be checked
141  * in the return opcode, we could inline simple methods that don't
142  * use the stack or local variables....
143  * 
144  * The {,.S} versions of many opcodes can/should be merged to reduce code
145  * duplication.
146  * 
147  * -fomit-frame-pointer gives about 2% speedup. 
148  */
149 static void 
150 ves_exec_method (MonoImage *image, MonoMethod *mh, stackval *args)
151 {
152         /*
153          * with alloca we get the expected huge performance gain
154          * stackval *stack = g_new0(stackval, mh->max_stack);
155          */
156         stackval *stack = alloca (sizeof (stackval) * mh->header->max_stack);
157         register const unsigned char *ip = mh->header->code;
158         register stackval *sp = stack;
159         /* FIXME: remove this hack */
160         static int fake_field = 42;
161         stackval *locals;
162         GOTO_LABEL_VARS;
163
164         if (mh->header->num_locals)
165                 locals = alloca (sizeof (stackval) * mh->header->num_locals);
166
167         /*
168          * using while (ip < end) may result in a 15% performance drop, 
169          * but it may be useful for debug
170          */
171         while (1) {
172                 /*count++;*/
173
174 #if DEBUG_INTERP
175                 g_print ("0x%04x %02x\n", ip-(unsigned char*)mh->header->code, *ip);
176                 if (sp > stack){
177                         printf ("\t[%d] %d 0x%08x %0.5f\n", sp-stack, sp[-1].type,
178                                 sp[-1].data.i, sp[-1].data.f);
179                 }
180 #endif
181                 
182                 SWITCH (*ip) {
183                 CASE (CEE_NOP) 
184                         ++ip;
185                         BREAK;
186                 CASE (CEE_BREAK)
187                         ++ip;
188                         G_BREAKPOINT (); /* this is not portable... */
189                         BREAK;
190                 CASE (CEE_LDARG_0)
191                 CASE (CEE_LDARG_1)
192                 CASE (CEE_LDARG_2)
193                 CASE (CEE_LDARG_3)
194                         *sp = args [(*ip)-CEE_LDARG_0];
195                         ++sp;
196                         ++ip;
197                         BREAK;
198                 CASE (CEE_LDLOC_0)
199                 CASE (CEE_LDLOC_1)
200                 CASE (CEE_LDLOC_2)
201                 CASE (CEE_LDLOC_3)
202                         *sp = locals [(*ip)-CEE_LDLOC_0];
203                         ++ip;
204                         ++sp;
205                         BREAK;
206                 CASE (CEE_STLOC_0)
207                 CASE (CEE_STLOC_1)
208                 CASE (CEE_STLOC_2)
209                 CASE (CEE_STLOC_3)
210                         --sp;
211                         locals [(*ip)-CEE_STLOC_0] = *sp;
212                         ++ip;
213                         BREAK;
214                 CASE (CEE_LDARG_S)
215                         ++ip;
216                         *sp = args [*ip];
217                         ++sp;
218                         ++ip;
219                         BREAK;
220                 CASE (CEE_LDARGA_S)
221                         ++ip;
222                         sp->type = VAL_TP;
223                         sp->data.p = &(args [*ip]);
224                         ++sp;
225                         ++ip;
226                         BREAK;
227                 CASE (CEE_STARG_S) ves_abort(); BREAK;
228                 CASE (CEE_LDLOC_S)
229                         ++ip;
230                         *sp = locals [*ip];
231                         ++sp;
232                         ++ip;
233                         BREAK;
234                 CASE (CEE_LDLOCA_S) ves_abort(); BREAK;
235                 CASE (CEE_STLOC_S)
236                         ++ip;
237                         --sp;
238                         locals [*ip] = *sp;
239                         ++ip;
240                         BREAK;
241                 CASE (CEE_LDNULL) 
242                         ++ip;
243                         sp->type = VAL_OBJ;
244                         sp->data.p = NULL;
245                         ++sp;
246                         BREAK;
247                 CASE (CEE_LDC_I4_M1)
248                         ++ip;
249                         sp->type = VAL_I32;
250                         sp->data.i = -1;
251                         ++sp;
252                         BREAK;
253                 CASE (CEE_LDC_I4_0)
254                 CASE (CEE_LDC_I4_1)
255                 CASE (CEE_LDC_I4_2)
256                 CASE (CEE_LDC_I4_3)
257                 CASE (CEE_LDC_I4_4)
258                 CASE (CEE_LDC_I4_5)
259                 CASE (CEE_LDC_I4_6)
260                 CASE (CEE_LDC_I4_7)
261                 CASE (CEE_LDC_I4_8)
262                         sp->type = VAL_I32;
263                         sp->data.i = (*ip) - CEE_LDC_I4_0;
264                         ++sp;
265                         ++ip;
266                         BREAK;
267                 CASE (CEE_LDC_I4_S) 
268                         ++ip;
269                         sp->type = VAL_I32;
270                         sp->data.i = *ip; /* FIXME: signed? */
271                         ++ip;
272                         ++sp;
273                         BREAK;
274                 CASE (CEE_LDC_I4)
275                         ++ip;
276                         sp->type = VAL_I32;
277                         sp->data.i = read32 (ip);
278                         ip += 4;
279                         ++sp;
280                         BREAK;
281                 CASE (CEE_LDC_I8)
282                         ++ip;
283                         sp->type = VAL_I64;
284                         sp->data.i = read64 (ip);
285                         ip += 8;
286                         ++sp;
287                         BREAK;
288                 CASE (CEE_LDC_R4)
289                         ++ip;
290                         sp->type = VAL_DOUBLE;
291                         /* FIXME: ENOENDIAN */
292                         sp->data.f = *(float*)(ip);
293                         ip += sizeof (float);
294                         ++sp;
295                         BREAK;
296                 CASE (CEE_LDC_R8) 
297                         ++ip;
298                         sp->type = VAL_DOUBLE;
299                         /* FIXME: ENOENDIAN */
300                         sp->data.f = *(double*) (ip);
301                         ip += sizeof (double);
302                         ++sp;
303                         BREAK;
304                 CASE (CEE_UNUSED99) ves_abort (); BREAK;
305                 CASE (CEE_DUP) 
306                         *sp = sp [-1]; 
307                         ++sp; 
308                         ++ip; 
309                         BREAK;
310                 CASE (CEE_POP)
311                         ++ip;
312                         --sp;
313                         BREAK;
314                 CASE (CEE_JMP) ves_abort(); BREAK;
315                 CASE (CEE_CALL) {
316                         MonoMethod *cmh;
317                         guint32 token;
318
319                         ++ip;
320                         token = read32 (ip);
321                         ip += 4;
322                         if (!(cmh = g_hash_table_lookup (method_cache, GINT_TO_POINTER (token)))) {
323                                 cmh = mono_get_method (image, token);
324                                 g_hash_table_insert (method_cache, GINT_TO_POINTER (token), cmh);
325                         }
326
327                         /* decrement by the actual number of args */
328                         sp -= cmh->signature->param_count;
329                         g_assert (cmh->signature->call_convention == MONO_CALL_DEFAULT);
330
331                         /* we need to truncate according to the type of args ... */
332                         ves_exec_method (image, cmh, sp);
333
334                         /* need to handle typedbyref ... */
335                         if (cmh->signature->ret->type)
336                                 sp++;
337                         BREAK;
338                 }
339                 CASE (CEE_CALLI) ves_abort(); BREAK;
340                 CASE (CEE_RET)
341                         --sp;
342                         *args = *sp;
343                         if (sp != stack)
344                                 g_warning ("more values on stack: %d", sp-stack);
345
346                         /*if (sp->type == VAL_DOUBLE)
347                                         g_print("%.9f\n", sp->data.f);*/
348                         /*g_free (stack);*/
349                         return;
350                 CASE (CEE_BR_S)
351                         ++ip;
352                         ip += (signed char) *ip;
353                         ++ip;
354                         BREAK;
355                 CASE (CEE_BRFALSE_S) {
356                         int result;
357                         ++ip;
358                         --sp;
359                         switch (sp->type) {
360                         case VAL_I32: result = sp->data.i == 0; break;
361                         case VAL_I64: result = sp->data.l == 0; break;
362                         case VAL_DOUBLE: result = sp->data.f ? 0: 1; break;
363                         default: result = sp->data.p == NULL; break;
364                         }
365                         if (result)
366                                 ip += (signed char)*ip;
367                         ++ip;
368                         BREAK;
369                 }
370                 CASE (CEE_BRTRUE_S) {
371                         int result;
372                         ++ip;
373                         --sp;
374                         switch (sp->type) {
375                         case VAL_I32: result = sp->data.i != 0; break;
376                         case VAL_I64: result = sp->data.l != 0; break;
377                         case VAL_DOUBLE: result = sp->data.f ? 1 : 0; break;
378                         default: result = sp->data.p != NULL; break;
379                         }
380                         if (result)
381                                 ip += (signed char)*ip;
382                         ++ip;
383                         BREAK;
384                 }
385                 CASE (CEE_BEQ_S) {
386                         int result;
387                         ++ip;
388                         sp -= 2;
389                         if (sp->type == VAL_I32)
390                                 result = sp [0].data.i == GET_NATI (sp [1]);
391                         else if (sp->type == VAL_I64)
392                                 result = sp [0].data.l == sp [1].data.l;
393                         else if (sp->type == VAL_DOUBLE)
394                                 result = sp [0].data.f == sp [1].data.f;
395                         else
396                                 result = GET_NATI (sp [0]) == GET_NATI (sp [1]);
397                         if (result)
398                                 ip += (signed char)*ip;
399                         ++ip;
400                         BREAK;
401                 }
402                 CASE (CEE_BGE_S) {
403                         int result;
404                         ++ip;
405                         sp -= 2;
406                         if (sp->type == VAL_I32)
407                                 result = sp [0].data.i >= GET_NATI (sp [1]);
408                         else if (sp->type == VAL_I64)
409                                 result = sp [0].data.l >= sp [1].data.l;
410                         else if (sp->type == VAL_DOUBLE)
411                                 result = sp [0].data.f >= sp [1].data.f;
412                         else
413                                 result = GET_NATI (sp [0]) >= GET_NATI (sp [1]);
414                         if (result)
415                                 ip += (signed char)*ip;
416                         ++ip;
417                         BREAK;
418                 }
419                 CASE (CEE_BGT_S) {
420                         int result;
421                         ++ip;
422                         sp -= 2;
423                         if (sp->type == VAL_I32)
424                                 result = sp [0].data.i > GET_NATI (sp [1]);
425                         else if (sp->type == VAL_I64)
426                                 result = sp [0].data.l > sp [1].data.l;
427                         else if (sp->type == VAL_DOUBLE)
428                                 result = sp [0].data.f > sp [1].data.f;
429                         else
430                                 result = GET_NATI (sp [0]) > GET_NATI (sp [1]);
431                         if (result)
432                                 ip += (signed char)*ip;
433                         ++ip;
434                         BREAK;
435                 }
436                 CASE (CEE_BLT_S) {
437                         int result;
438                         ++ip;
439                         sp -= 2;
440                         if (sp->type == VAL_I32)
441                                 result = sp[0].data.i < GET_NATI(sp[1]);
442                         else if (sp->type == VAL_I64)
443                                 result = sp[0].data.l < sp[1].data.l;
444                         else if (sp->type == VAL_DOUBLE)
445                                 result = sp[0].data.f < sp[1].data.f;
446                         else
447                                 result = GET_NATI(sp[0]) < GET_NATI(sp[1]);
448                         if (result)
449                                 ip += (signed char)*ip;
450                         ++ip;
451                         BREAK;
452                 }
453                 CASE (CEE_BLE_S) {
454                         int result;
455                         ++ip;
456                         sp -= 2;
457
458                         if (sp->type == VAL_I32)
459                                 result = sp [0].data.i <= GET_NATI (sp [1]);
460                         else if (sp->type == VAL_I64)
461                                 result = sp [0].data.l <= sp [1].data.l;
462                         else if (sp->type == VAL_DOUBLE)
463                                 result = sp [0].data.f <= sp [1].data.f;
464                         else {
465                                 /*
466                                  * FIXME: here and in other places GET_NATI on the left side 
467                                  * _will_ be wrong when we change the macro to work on 64 buts 
468                                  * systems.
469                                  */
470                                 result = GET_NATI (sp [0]) <= GET_NATI (sp [1]);
471                         }
472                         if (result)
473                                 ip += (signed char)*ip;
474                         ++ip;
475                         BREAK;
476                 }
477                 CASE (CEE_BNE_UN_S) ves_abort(); BREAK;
478                 CASE (CEE_BGE_UN_S) ves_abort(); BREAK;
479                 CASE (CEE_BGT_UN_S) ves_abort(); BREAK;
480                 CASE (CEE_BLE_UN_S) ves_abort(); BREAK;
481                 CASE (CEE_BLT_UN_S) ves_abort(); BREAK;
482                 CASE (CEE_BR) ves_abort(); BREAK;
483                 CASE (CEE_BRFALSE) ves_abort(); BREAK;
484                 CASE (CEE_BRTRUE) ves_abort(); BREAK;
485                 CASE (CEE_BEQ) ves_abort(); BREAK;
486                 CASE (CEE_BGE) ves_abort(); BREAK;
487                 CASE (CEE_BGT) ves_abort(); BREAK;
488                 CASE (CEE_BLE) ves_abort(); BREAK;
489                 CASE (CEE_BLT) ves_abort(); BREAK;
490                 CASE (CEE_BNE_UN) ves_abort(); BREAK;
491                 CASE (CEE_BGE_UN) ves_abort(); BREAK;
492                 CASE (CEE_BGT_UN) ves_abort(); BREAK;
493                 CASE (CEE_BLE_UN) ves_abort(); BREAK;
494                 CASE (CEE_BLT_UN) ves_abort(); BREAK;
495                 CASE (CEE_SWITCH) {
496                         guint32 n;
497                         const unsigned char *st;
498                         ++ip;
499                         n = read32 (ip);
500                         ip += 4;
501                         st = ip + sizeof (gint32) * n;
502                         --sp;
503                         if ((guint32)sp->data.i < n) {
504                                 gint offset;
505                                 ip += sizeof (gint32) * (guint32)sp->data.i;
506                                 offset = read32 (ip);
507                                 ip = st + offset;
508                         } else {
509                                 ip = st;
510                         }
511                         BREAK;
512                 }
513                 CASE (CEE_LDIND_I1) ves_abort(); BREAK;
514                 CASE (CEE_LDIND_U1) ves_abort(); BREAK;
515                 CASE (CEE_LDIND_I2) ves_abort(); BREAK;
516                 CASE (CEE_LDIND_U2) ves_abort(); BREAK;
517                 CASE (CEE_LDIND_I4) ves_abort(); BREAK;
518                 CASE (CEE_LDIND_U4) ves_abort(); BREAK;
519                 CASE (CEE_LDIND_I8) ves_abort(); BREAK;
520                 CASE (CEE_LDIND_I) ves_abort(); BREAK;
521                 CASE (CEE_LDIND_R4) ves_abort(); BREAK;
522                 CASE (CEE_LDIND_R8) ves_abort(); BREAK;
523                 CASE (CEE_LDIND_REF) ves_abort(); BREAK;
524                 CASE (CEE_STIND_REF) ves_abort(); BREAK;
525                 CASE (CEE_STIND_I1) ves_abort(); BREAK;
526                 CASE (CEE_STIND_I2) ves_abort(); BREAK;
527                 CASE (CEE_STIND_I4) ves_abort(); BREAK;
528                 CASE (CEE_STIND_I8) ves_abort(); BREAK;
529                 CASE (CEE_STIND_R4) ves_abort(); BREAK;
530                 CASE (CEE_STIND_R8) ves_abort(); BREAK;
531                 CASE (CEE_ADD)
532                         ++ip;
533                         --sp;
534                         /* should probably consider the pointers as unsigned */
535                         if (sp->type == VAL_I32)
536                                 sp [-1].data.i += GET_NATI (sp [0]);
537                         else if (sp->type == VAL_I64)
538                                 sp [-1].data.l += sp [0].data.l;
539                         else if (sp->type == VAL_DOUBLE)
540                                 sp [-1].data.f += sp [0].data.f;
541                         else
542                                 (char*)sp [-1].data.p += GET_NATI (sp [0]);
543                         BREAK;
544                 CASE (CEE_SUB)
545                         ++ip;
546                         --sp;
547                         /* should probably consider the pointers as unsigned */
548                         if (sp->type == VAL_I32)
549                                 sp [-1].data.i -= GET_NATI (sp [0]);
550                         else if (sp->type == VAL_I64)
551                                 sp [-1].data.l -= sp [0].data.l;
552                         else if (sp->type == VAL_DOUBLE)
553                                 sp [-1].data.f -= sp [0].data.f;
554                         else
555                                 (char*)sp [-1].data.p -= GET_NATI (sp [0]);
556                         BREAK;
557                 CASE (CEE_MUL)
558                         ++ip;
559                         --sp;
560                         if (sp->type == VAL_I32)
561                                 sp [-1].data.i *= GET_NATI (sp [0]);
562                         else if (sp->type == VAL_I64)
563                                 sp [-1].data.l *= sp [0].data.l;
564                         else if (sp->type == VAL_DOUBLE)
565                                 sp [-1].data.f *= sp [0].data.f;
566                         BREAK;
567                 CASE (CEE_DIV)
568                         ++ip;
569                         --sp;
570                         if (sp->type == VAL_I32)
571                                 sp [-1].data.i /= GET_NATI (sp [0]);
572                         else if (sp->type == VAL_I64)
573                                 sp [-1].data.l /= sp [0].data.l;
574                         else if (sp->type == VAL_DOUBLE)
575                                 sp [-1].data.f /= sp [0].data.f;
576                         BREAK;
577                 CASE (CEE_DIV_UN)
578                         ++ip;
579                         --sp;
580                         if (sp->type == VAL_I32)
581                                 (guint32)sp [-1].data.i /= (guint32)GET_NATI (sp [0]);
582                         else if (sp->type == VAL_I64)
583                                 (guint64)sp [-1].data.l /= (guint64)sp [0].data.l;
584                         else if (sp->type == VAL_NATI)
585                                 (gulong)sp [-1].data.p /= (gulong)sp [0].data.p;
586                         BREAK;
587                 CASE (CEE_REM)
588                         ++ip;
589                         --sp;
590                         if (sp->type == VAL_I32)
591                                 sp [-1].data.i %= GET_NATI (sp [0]);
592                         else if (sp->type == VAL_I64)
593                                 sp [-1].data.l %= sp [0].data.l;
594                         else if (sp->type == VAL_DOUBLE)
595                                 /* FIXME: what do we actually fo here? */
596                                 sp [-1].data.f = 0;
597                         else
598                                 GET_NATI (sp [-1]) %= GET_NATI (sp [0]);
599                         BREAK;
600                 CASE (CEE_REM_UN) ves_abort(); BREAK;
601                 CASE (CEE_AND)
602                         ++ip;
603                         --sp;
604                         if (sp->type == VAL_I32)
605                                 sp [-1].data.i &= GET_NATI (sp [0]);
606                         else if (sp->type == VAL_I64)
607                                 sp [-1].data.l &= sp [0].data.l;
608                         else
609                                 GET_NATI (sp [-1]) &= GET_NATI (sp [0]);
610                         BREAK;
611                 CASE (CEE_OR)
612                         ++ip;
613                         --sp;
614                         if (sp->type == VAL_I32)
615                                 sp [-1].data.i |= GET_NATI (sp [0]);
616                         else if (sp->type == VAL_I64)
617                                 sp [-1].data.l |= sp [0].data.l;
618                         else
619                                 GET_NATI (sp [-1]) |= GET_NATI (sp [0]);
620                         BREAK;
621                 CASE (CEE_XOR)
622                         ++ip;
623                         --sp;
624                         if (sp->type == VAL_I32)
625                                 sp [-1].data.i ^= GET_NATI (sp [0]);
626                         else if (sp->type == VAL_I64)
627                                 sp [-1].data.l ^= sp [0].data.l;
628                         else
629                                 GET_NATI (sp [-1]) ^= GET_NATI (sp [0]);
630                         BREAK;
631                 CASE (CEE_SHL)
632                         ++ip;
633                         --sp;
634                         if (sp->type == VAL_I32)
635                                 sp [-1].data.i <<= GET_NATI (sp [0]);
636                         else if (sp->type == VAL_I64)
637                                 sp [-1].data.l <<= GET_NATI (sp [0]);
638                         else
639                                 GET_NATI (sp [-1]) <<= GET_NATI (sp [0]);
640                         BREAK;
641                 CASE (CEE_SHR)
642                         ++ip;
643                         --sp;
644                         if (sp->type == VAL_I32)
645                                 sp [-1].data.i >>= GET_NATI (sp [0]);
646                         else if (sp->type == VAL_I64)
647                                 sp [-1].data.l >>= GET_NATI (sp [0]);
648                         else
649                                 GET_NATI (sp [-1]) >>= GET_NATI (sp [0]);
650                         BREAK;
651                 CASE (CEE_SHR_UN) ves_abort(); BREAK;
652                 CASE (CEE_NEG)
653                         ++ip;
654                         if (sp->type == VAL_I32)
655                                 sp->data.i = - sp->data.i;
656                         else if (sp->type == VAL_I64)
657                                 sp->data.l = - sp->data.l;
658                         else if (sp->type == VAL_DOUBLE)
659                                 sp->data.f = - sp->data.f;
660                         else if (sp->type == VAL_NATI)
661                                 sp->data.p = (gpointer)(- (nati_t)sp->data.p);
662                         BREAK;
663                 CASE (CEE_NOT)
664                         ++ip;
665                         if (sp->type == VAL_I32)
666                                 sp->data.i = ~ sp->data.i;
667                         else if (sp->type == VAL_I64)
668                                 sp->data.l = ~ sp->data.l;
669                         else if (sp->type == VAL_NATI)
670                                 sp->data.p = (gpointer)(~ (nati_t)sp->data.p);
671                         BREAK;
672                 CASE (CEE_CONV_I1) ves_abort(); BREAK;
673                 CASE (CEE_CONV_I2) ves_abort(); BREAK;
674                 CASE (CEE_CONV_I4)
675                         ++ip;
676                         /* FIXME: handle other cases. what about sign? */
677                         if (sp [-1].type == VAL_DOUBLE) {
678                                 sp [-1].data.i = (gint32)sp [-1].data.f;
679                                 sp [-1].type = VAL_I32;
680                         } else {
681                                 ves_abort();
682                         }
683                         BREAK;
684                 CASE (CEE_CONV_I8) ves_abort(); BREAK;
685                 CASE (CEE_CONV_R4) ves_abort(); BREAK;
686                 CASE (CEE_CONV_R8)
687                         ++ip;
688                         /* FIXME: handle other cases. what about sign? */
689                         if (sp [-1].type == VAL_I32) {
690                                 sp [-1].data.f = (double)sp [-1].data.i;
691                                 sp [-1].type = VAL_DOUBLE;
692                         } else {
693                                 ves_abort();
694                         }
695                         BREAK;
696                 CASE (CEE_CONV_U4)
697                         ++ip;
698                         /* FIXME: handle other cases. what about sign? */
699                         if (sp [-1].type == VAL_DOUBLE) {
700                                 sp [-1].data.i = (guint32)sp [-1].data.f;
701                                 sp [-1].type = VAL_I32;
702                         } else {
703                                 ves_abort();
704                         }
705                         BREAK;
706                 CASE (CEE_CONV_U8) ves_abort(); BREAK;
707                 CASE (CEE_CALLVIRT) ves_abort(); BREAK;
708                 CASE (CEE_CPOBJ) ves_abort(); BREAK;
709                 CASE (CEE_LDOBJ) ves_abort(); BREAK;
710                 CASE (CEE_LDSTR) ves_abort(); BREAK;
711
712                 CASE (CEE_NEWOBJ) {
713                         MonoObject *o;
714                         guint32 token;
715
716                         ip++;
717                         token = read32 (ip);
718                         o = newobj (image, token);
719                         ip += 4;
720                         BREAK;
721                 }
722                 
723                 CASE (CEE_CASTCLASS) ves_abort(); BREAK;
724                 CASE (CEE_ISINST) ves_abort(); BREAK;
725                 CASE (CEE_CONV_R_UN) ves_abort(); BREAK;
726                 CASE (CEE_UNUSED58) ves_abort(); BREAK;
727                 CASE (CEE_UNUSED1) ves_abort(); BREAK;
728                 CASE (CEE_UNBOX) ves_abort(); BREAK;
729                 CASE (CEE_THROW) ves_abort(); BREAK;
730                 CASE (CEE_LDFLD) ves_abort(); BREAK;
731                 CASE (CEE_LDFLDA) ves_abort(); BREAK;
732                 CASE (CEE_STFLD) ves_abort(); BREAK;
733                 CASE (CEE_LDSFLD)
734                         /* FIXME: get the real field here */
735                         ip += 5;
736                         sp->type = VAL_I32;
737                         sp->data.i = fake_field;
738                         ++sp;
739                         BREAK;
740                 CASE (CEE_LDSFLDA) ves_abort(); BREAK;
741                 CASE (CEE_STSFLD)
742                         /* FIXME: get the real field here */
743                         ip += 5;
744                         --sp;
745                         fake_field = sp->data.i;
746                         BREAK;
747                 CASE (CEE_STOBJ) ves_abort(); BREAK;
748                 CASE (CEE_CONV_OVF_I1_UN) ves_abort(); BREAK;
749                 CASE (CEE_CONV_OVF_I2_UN) ves_abort(); BREAK;
750                 CASE (CEE_CONV_OVF_I4_UN) ves_abort(); BREAK;
751                 CASE (CEE_CONV_OVF_I8_UN) ves_abort(); BREAK;
752                 CASE (CEE_CONV_OVF_U1_UN) ves_abort(); BREAK;
753                 CASE (CEE_CONV_OVF_U2_UN) ves_abort(); BREAK;
754                 CASE (CEE_CONV_OVF_U4_UN) ves_abort(); BREAK;
755                 CASE (CEE_CONV_OVF_U8_UN) ves_abort(); BREAK;
756                 CASE (CEE_CONV_OVF_I_UN) ves_abort(); BREAK;
757                 CASE (CEE_CONV_OVF_U_UN) ves_abort(); BREAK;
758                 CASE (CEE_BOX) ves_abort(); BREAK;
759                 CASE (CEE_NEWARR) ves_abort(); BREAK;
760                 CASE (CEE_LDLEN) ves_abort(); BREAK;
761                 CASE (CEE_LDELEMA) ves_abort(); BREAK;
762                 CASE (CEE_LDELEM_I1) ves_abort(); BREAK;
763                 CASE (CEE_LDELEM_U1) ves_abort(); BREAK;
764                 CASE (CEE_LDELEM_I2) ves_abort(); BREAK;
765                 CASE (CEE_LDELEM_U2) ves_abort(); BREAK;
766                 CASE (CEE_LDELEM_I4) ves_abort(); BREAK;
767                 CASE (CEE_LDELEM_U4) ves_abort(); BREAK;
768                 CASE (CEE_LDELEM_I8) ves_abort(); BREAK;
769                 CASE (CEE_LDELEM_I) ves_abort(); BREAK;
770                 CASE (CEE_LDELEM_R4) ves_abort(); BREAK;
771                 CASE (CEE_LDELEM_R8) ves_abort(); BREAK;
772                 CASE (CEE_LDELEM_REF) ves_abort(); BREAK;
773                 CASE (CEE_STELEM_I) ves_abort(); BREAK;
774                 CASE (CEE_STELEM_I1) ves_abort(); BREAK;
775                 CASE (CEE_STELEM_I2) ves_abort(); BREAK;
776                 CASE (CEE_STELEM_I4) ves_abort(); BREAK;
777                 CASE (CEE_STELEM_I8) ves_abort(); BREAK;
778                 CASE (CEE_STELEM_R4) ves_abort(); BREAK;
779                 CASE (CEE_STELEM_R8) ves_abort(); BREAK;
780                 CASE (CEE_STELEM_REF) ves_abort(); BREAK;
781                 CASE (CEE_UNUSED2) 
782                 CASE (CEE_UNUSED3) 
783                 CASE (CEE_UNUSED4) 
784                 CASE (CEE_UNUSED5) 
785                 CASE (CEE_UNUSED6) 
786                 CASE (CEE_UNUSED7) 
787                 CASE (CEE_UNUSED8) 
788                 CASE (CEE_UNUSED9) 
789                 CASE (CEE_UNUSED10) 
790                 CASE (CEE_UNUSED11) 
791                 CASE (CEE_UNUSED12) 
792                 CASE (CEE_UNUSED13) 
793                 CASE (CEE_UNUSED14) 
794                 CASE (CEE_UNUSED15) 
795                 CASE (CEE_UNUSED16) 
796                 CASE (CEE_UNUSED17) ves_abort(); BREAK;
797                 CASE (CEE_CONV_OVF_I1) ves_abort(); BREAK;
798                 CASE (CEE_CONV_OVF_U1) ves_abort(); BREAK;
799                 CASE (CEE_CONV_OVF_I2) ves_abort(); BREAK;
800                 CASE (CEE_CONV_OVF_U2) ves_abort(); BREAK;
801                 CASE (CEE_CONV_OVF_I4) ves_abort(); BREAK;
802                 CASE (CEE_CONV_OVF_U4) ves_abort(); BREAK;
803                 CASE (CEE_CONV_OVF_I8) ves_abort(); BREAK;
804                 CASE (CEE_CONV_OVF_U8) ves_abort(); BREAK;
805                 CASE (CEE_UNUSED50) 
806                 CASE (CEE_UNUSED18) 
807                 CASE (CEE_UNUSED19) 
808                 CASE (CEE_UNUSED20) 
809                 CASE (CEE_UNUSED21) 
810                 CASE (CEE_UNUSED22) 
811                 CASE (CEE_UNUSED23) ves_abort(); BREAK;
812                 CASE (CEE_REFANYVAL) ves_abort(); BREAK;
813                 CASE (CEE_CKFINITE) ves_abort(); BREAK;
814                 CASE (CEE_UNUSED24) ves_abort(); BREAK;
815                 CASE (CEE_UNUSED25) ves_abort(); BREAK;
816                 CASE (CEE_MKREFANY) ves_abort(); BREAK;
817                 CASE (CEE_UNUSED59) 
818                 CASE (CEE_UNUSED60) 
819                 CASE (CEE_UNUSED61) 
820                 CASE (CEE_UNUSED62) 
821                 CASE (CEE_UNUSED63) 
822                 CASE (CEE_UNUSED64) 
823                 CASE (CEE_UNUSED65) 
824                 CASE (CEE_UNUSED66) 
825                 CASE (CEE_UNUSED67) ves_abort(); BREAK;
826                 CASE (CEE_LDTOKEN) ves_abort(); BREAK;
827                 CASE (CEE_CONV_U2) ves_abort(); BREAK;
828                 CASE (CEE_CONV_U1) ves_abort(); BREAK;
829                 CASE (CEE_CONV_I) ves_abort(); BREAK;
830                 CASE (CEE_CONV_OVF_I) ves_abort(); BREAK;
831                 CASE (CEE_CONV_OVF_U) ves_abort(); BREAK;
832                 CASE (CEE_ADD_OVF) ves_abort(); BREAK;
833                 CASE (CEE_ADD_OVF_UN) ves_abort(); BREAK;
834                 CASE (CEE_MUL_OVF) ves_abort(); BREAK;
835                 CASE (CEE_MUL_OVF_UN) ves_abort(); BREAK;
836                 CASE (CEE_SUB_OVF) ves_abort(); BREAK;
837                 CASE (CEE_SUB_OVF_UN) ves_abort(); BREAK;
838                 CASE (CEE_ENDFINALLY) ves_abort(); BREAK;
839                 CASE (CEE_LEAVE) ves_abort(); BREAK;
840                 CASE (CEE_LEAVE_S) ves_abort(); BREAK;
841                 CASE (CEE_STIND_I) ves_abort(); BREAK;
842                 CASE (CEE_CONV_U) ves_abort(); BREAK;
843                 CASE (CEE_UNUSED26) 
844                 CASE (CEE_UNUSED27) 
845                 CASE (CEE_UNUSED28) 
846                 CASE (CEE_UNUSED29) 
847                 CASE (CEE_UNUSED30) 
848                 CASE (CEE_UNUSED31) 
849                 CASE (CEE_UNUSED32) 
850                 CASE (CEE_UNUSED33) 
851                 CASE (CEE_UNUSED34) 
852                 CASE (CEE_UNUSED35) 
853                 CASE (CEE_UNUSED36) 
854                 CASE (CEE_UNUSED37) 
855                 CASE (CEE_UNUSED38) 
856                 CASE (CEE_UNUSED39) 
857                 CASE (CEE_UNUSED40) 
858                 CASE (CEE_UNUSED41) 
859                 CASE (CEE_UNUSED42) 
860                 CASE (CEE_UNUSED43) 
861                 CASE (CEE_UNUSED44) 
862                 CASE (CEE_UNUSED45) 
863                 CASE (CEE_UNUSED46) 
864                 CASE (CEE_UNUSED47) 
865                 CASE (CEE_UNUSED48) ves_abort(); BREAK;
866                 CASE (CEE_PREFIX7) ves_abort(); BREAK;
867                 CASE (CEE_PREFIX6) ves_abort(); BREAK;
868                 CASE (CEE_PREFIX5) ves_abort(); BREAK;
869                 CASE (CEE_PREFIX4) ves_abort(); BREAK;
870                 CASE (CEE_PREFIX3) ves_abort(); BREAK;
871                 CASE (CEE_PREFIX2) ves_abort(); BREAK;
872                 CASE (CEE_PREFIXREF) ves_abort(); BREAK;
873                 SUB_SWITCH
874                         ++ip;
875                         switch (*ip) {
876                         case CEE_ARGLIST: ves_abort(); break;
877                         case CEE_CEQ: ves_abort(); break;
878                         case CEE_CGT: ves_abort(); break;
879                         case CEE_CGT_UN: ves_abort(); break;
880                         case CEE_CLT: ves_abort(); break;
881                         case CEE_CLT_UN: ves_abort(); break;
882                         case CEE_LDFTN: ves_abort(); break;
883                         case CEE_LDVIRTFTN: ves_abort(); break;
884                         case CEE_UNUSED56: ves_abort(); break;
885                         case CEE_LDARG: ves_abort(); break;
886                         case CEE_LDARGA: ves_abort(); break;
887                         case CEE_STARG: ves_abort(); break;
888                         case CEE_LDLOC: ves_abort(); break;
889                         case CEE_LDLOCA: ves_abort(); break;
890                         case CEE_STLOC: ves_abort(); break;
891                         case CEE_LOCALLOC: ves_abort(); break;
892                         case CEE_UNUSED57: ves_abort(); break;
893                         case CEE_ENDFILTER: ves_abort(); break;
894                         case CEE_UNALIGNED_: ves_abort(); break;
895                         case CEE_VOLATILE_: ves_abort(); break;
896                         case CEE_TAIL_: ves_abort(); break;
897                         case CEE_INITOBJ: ves_abort(); break;
898                         case CEE_UNUSED68: ves_abort(); break;
899                         case CEE_CPBLK: ves_abort(); break;
900                         case CEE_INITBLK: ves_abort(); break;
901                         case CEE_UNUSED69: ves_abort(); break;
902                         case CEE_RETHROW: ves_abort(); break;
903                         case CEE_UNUSED: ves_abort(); break;
904                         case CEE_SIZEOF: ves_abort(); break;
905                         case CEE_REFANYTYPE: ves_abort(); break;
906                         case CEE_UNUSED52: 
907                         case CEE_UNUSED53: 
908                         case CEE_UNUSED54: 
909                         case CEE_UNUSED55: 
910                         case CEE_UNUSED70: 
911                         default:
912                                 g_error ("Unimplemented opcode: 0xFE %02x at 0x%x\n", *ip, ip-(unsigned char*)mh->header->code);
913                         }
914                         continue;
915                 DEFAULT;
916                 }
917         }
918
919         g_assert_not_reached ();
920 }
921
922 static int 
923 ves_exec (MonoAssembly *assembly)
924 {
925         MonoImage *image = assembly->image;
926         cli_image_info_t *iinfo;
927         stackval result;
928         MonoMethod *mh;
929
930         iinfo = image->image_info;
931         
932         /* we need to exec the class and object constructors... */
933         method_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
934
935         mh = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point);
936         ves_exec_method (image, mh, &result);
937         fprintf (stderr, "result: %d\n", result.data.i);
938         mono_free_method (mh);
939
940         return 0;
941 }
942
943 static void
944 usage (void)
945 {
946         fprintf (stderr, "Usage is: mono-int executable args...");
947         exit (1);
948 }
949
950 int 
951 main (int argc, char *argv [])
952 {
953         MonoAssembly *assembly;
954         int retval = 0;
955         char *file;
956
957         if (argc < 2)
958                 usage ();
959
960         file = argv [1];
961
962         assembly = mono_assembly_open (file, NULL, NULL);
963         if (!assembly){
964                 fprintf (stderr, "Can not open image %s\n", file);
965                 exit (1);
966         }
967         retval = ves_exec (assembly);
968         mono_assembly_close (assembly);
969         printf("count: %d\n", count);
970
971         return retval;
972 }
973
974
975