* vm/class.h: Added.
[cacao.git] / src / vm / jit / intrp / engine.c
1 #include <assert.h>
2
3 /*  #define VM_DEBUG */
4 #define USE_spTOS
5
6 #include "arch.h"
7 #include "vm/jit/intrp/intrp.h"
8
9 #include "md-abi.h"                           /* required for TRACE_ARGS_NUM */
10
11 #include "cacao/cacao.h"
12 #include "vm/builtin.h"
13 #include "vm/exceptions.h"
14 #include "vm/loader.h"
15 #include "vm/options.h"
16 #include "vm/jit/codegen.inc.h"
17 #include "vm/jit/methodheader.h"
18 #include "vm/jit/patcher.h"
19
20 #define FFCALL 0
21
22 #if FFCALL
23 # include "ffcall/avcall/avcall.h"
24 #else
25 # include "libffi/include/ffi.h"
26 #endif
27
28 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
29 # ifndef USE_MD_THREAD_STUFF
30 #  include "machine-instr.h"
31 # else
32 #  include "threads/native/generic-primitives.h"
33 # endif
34 #endif
35
36 #if !defined(STORE_ORDER_BARRIER) && !defined(USE_THREADS)
37 #define STORE_ORDER_BARRIER() /* nothing */
38 #endif
39
40
41 /* threading macros */
42 #  define NEXT_P0
43 #  define IP            (ip)
44 #  define SET_IP(p)     ({ip=(p); NEXT_P0;})
45 #  define NEXT_INST     (*IP)
46 #  define INC_IP(const_inc)     ({ ip+=(const_inc);})
47 #  define DEF_CA
48 #  define NEXT_P1       
49 #  define NEXT_P2       ({goto **(ip++);})
50 #  define EXEC(XT)      ({goto *(XT);})
51
52 #define NEXT ({DEF_CA NEXT_P1; NEXT_P2;})
53 #define IPTOS NEXT_INST
54
55 #if defined(USE_spTOS)
56 #define IF_spTOS(x) x
57 #else
58 #define IF_spTOS(x)
59 #define spTOS (sp[0])
60 #endif
61
62 /* conversion on fetch */
63
64 #ifdef VM_PROFILING
65 #define SUPER_END  vm_count_block(IP)
66 #else
67 #define SUPER_END
68 #define vm_uncount_block(_ip)   /* nothing */
69 #endif
70
71 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
72
73 #define global_sp    (*(Cell **)&(THREADINFO->_global_sp))
74
75 #else /* defined(USE_THREADS) && defined(NATIVE_THREADS) */
76
77 #define MAX_STACK_SIZE 128*1024
78 static char stack[MAX_STACK_SIZE];
79
80 static Cell *_global_sp = (Cell *)(stack+MAX_STACK_SIZE);
81 #define global_sp    _global_sp
82
83 #endif /* defined(USE_THREADS) && defined(NATIVE_THREADS) */
84
85 #define CLEAR_global_sp (global_sp=NULL)
86
87
88 #define THROW0       goto throw
89 #define THROW(_ball) \
90     { \
91         global_sp = sp; \
92         *exceptionptr = (stacktrace_inline_##_ball(NULL, (u1 *) fp, (functionptr) IP, (functionptr) IP)); \
93         CLEAR_global_sp; \
94         THROW0; \
95     }
96
97 #define CHECK_NULL_PTR(ptr) \
98     { \
99         if ((ptr) == NULL) { \
100             THROW(nullpointerexception); \
101             } \
102         }
103
104 #define CHECK_OUT_OF_BOUNDS(_array, _idx)              \
105         {                                            \
106           if (length_array(_array) <= (u4) (_idx)) { \
107             global_sp = sp; \
108             *exceptionptr = stacktrace_inline_arrayindexoutofboundsexception(NULL, (u1 *) fp, (functionptr) IP, (functionptr) IP, _idx); \
109                     CLEAR_global_sp; \
110             THROW0; \
111           } \
112         }
113
114 #define CHECK_ZERO_DIVISOR(_divisor) \
115   { if (_divisor == 0) \
116       THROW(arithmeticexception); \
117   } 
118
119 #define access_local_int(_offset) \
120         ( *(Cell*)(((u1 *)fp) + (_offset)) )
121
122 #define access_local_ref(_offset) \
123         ( *(void **)(((u1 *)fp) + (_offset)) )
124
125 #define access_local_cell(_offset) \
126         ( *(Cell *)(((u1 *)fp) + (_offset)) )
127
128 #if 0
129 /* !! alignment bug */
130 #define access_local_long(_offset) \
131         ( *(s8 *)(((u1 *)fp) + (_offset)) )
132 #endif
133
134 #define length_array(array)                          \
135         ( ((java_arrayheader*)(array))->size )
136
137 #define access_array_int(array, index)               \
138         ((((java_intarray*)(array))->data)[index])
139
140 #define access_array_long(array, index)               \
141         ((((java_longarray*)(array))->data)[index])
142
143 #define access_array_char(array, index)               \
144         ((((java_chararray*)(array))->data)[index])
145
146 #define access_array_short(array, index)               \
147         ((((java_shortarray*)(array))->data)[index])
148
149 #define access_array_byte(array, index)               \
150         ((((java_bytearray*)(array))->data)[index])
151
152 #define access_array_addr(array, index)               \
153         ((((java_objectarray*)(array))->data)[index])
154
155 #define MAXLOCALS(stub) (((Cell *)stub)[1])
156
157 #if 0
158 #define CLEARSTACK(_start, _end) \
159          do {Cell *__start=(_start); MSET(__start,0,u1,(_end)-__start); } while (0)
160 #else
161 #define CLEARSTACK(_start, _end)
162 #endif
163
164
165 #if !FFCALL
166 ffi_type *cacaotype2ffitype(s4 cacaotype)
167 {
168         switch (cacaotype) {
169         case TYPE_INT:
170                 return &ffi_type_uint;
171         case TYPE_LNG:
172                 return &ffi_type_sint64;
173         case TYPE_FLT:
174                 return &ffi_type_float;
175         case TYPE_DBL:
176                 return &ffi_type_double;
177         case TYPE_ADR:
178                 return &ffi_type_pointer;
179         case TYPE_VOID:
180                 return &ffi_type_void;
181         default:
182                 assert(false);
183         }
184 }
185 #endif
186
187
188 /* call jni function */
189 static Cell *nativecall(functionptr f, methodinfo *m, Cell *sp, Inst *ra, Cell *fp, u1 *addrcif)
190 {
191 #if FFCALL
192         av_alist alist;
193         methoddesc *md;
194         Cell *p;
195         Cell *endsp;
196         s4 i;
197
198         struct {
199                 stackframeinfo sfi;
200                 localref_table lrt;
201         } s;
202
203         md = m->parseddesc;
204
205         switch (md->returntype.type) {
206         case TYPE_INT:
207                 endsp = sp - 1 + md->paramslots;
208                 av_start_int(alist, f, endsp);
209                 break;
210         case TYPE_LNG:
211                 endsp = sp - 2 + md->paramslots;
212                 av_start_longlong(alist, f, endsp);
213                 break;
214         case TYPE_FLT:
215                 endsp = sp - 1 + md->paramslots;
216                 av_start_float(alist, f, endsp);
217                 break;
218         case TYPE_DBL:
219                 endsp = sp - 2 + md->paramslots;
220                 av_start_double(alist, f, endsp);
221                 break;
222         case TYPE_ADR:
223                 endsp = sp - 1 + md->paramslots;
224                 av_start_ptr(alist, f, void *, endsp);
225                 break;
226         case TYPE_VOID:
227                 endsp = sp + md->paramslots;
228                 av_start_void(alist, f);
229                 break;
230         default:
231                 assert(false);
232         }
233
234         av_ptr(alist, JNIEnv *, &env);
235
236         if (m->flags & ACC_STATIC)
237                 av_ptr(alist, classinfo *, m->class);
238
239         for (i = 0, p = sp + md->paramslots; i < md->paramcount; i++) {
240                 switch (md->paramtypes[i].type) {
241                 case TYPE_INT:
242                         p -= 1;
243                         av_int(alist, *p);
244                         break;
245                 case TYPE_LNG:
246                         p -= 2;
247                         av_longlong(alist, *(s8 *)p);
248                         break;
249                 case TYPE_FLT:
250                         p -= 1;
251                         av_float(alist, *(float *) p);
252                         break;
253                 case TYPE_DBL:
254                         p -= 2;
255                         av_double(alist, *(double *) p);
256                         break;
257                 case TYPE_ADR:
258                         p -= 1;
259                         av_ptr(alist, void *, *(void **) p);
260                         break;
261                 default:
262                         assert(false);
263                 }
264         }
265
266         global_sp = sp;
267
268         /* create stackframe info structure */
269
270         codegen_start_native_call(&s, (u1 *) m->entrypoint,
271                                                           (u1 *) fp,
272                                                           (functionptr) ra);
273
274         av_call(alist);
275
276         codegen_finish_native_call(&s);
277
278         CLEAR_global_sp;
279
280         return endsp;
281 #else
282         methoddesc  *md = m->parseddesc; 
283         ffi_cif     *pcif;
284         void        *values[md->paramcount + 2];
285         void       **pvalues = values;
286         Cell        *p;
287         Cell        *endsp;
288         s4           i;
289         JNIEnv      *penv;
290
291         struct {
292                 stackframeinfo sfi;
293                 localref_table lrt;
294         } s;
295
296         pcif = (ffi_cif *) addrcif;
297
298         /* pass env pointer */
299
300         penv = (JNIEnv *) &env;
301         *pvalues++ = &penv;
302
303         /* for static methods, pass class pointer */
304
305         if (m->flags & ACC_STATIC) {
306                 *pvalues++ = &m->class;
307         }
308
309         /* pass parameter to native function */
310
311         for (i = 0, p = sp + md->paramslots; i < md->paramcount; i++) {
312                 if (IS_2_WORD_TYPE(md->paramtypes[i].type))
313                         p -= 2;
314                 else
315                         p--;
316
317                 *pvalues++ = p;
318         }
319
320         /* calculate position of return value */
321
322         if (md->returntype.type == TYPE_VOID)
323                 endsp = sp + md->paramslots;
324         else
325                 endsp = sp - (IS_2_WORD_TYPE(md->returntype.type) ? 2 : 1) + md->paramslots;
326
327         global_sp = sp;
328
329         /* create stackframe info structure */
330
331         codegen_start_native_call((u1 *) (((ptrint ) &s) + sizeof(s)),
332                                                           (u1 *) (ptrint) m->entrypoint,
333                                                           (u1 *) fp, (u1 *) ra);
334
335         ffi_call(pcif, FFI_FN(f), endsp, values);
336
337         codegen_finish_native_call((u1 *) (((ptrint) &s) + sizeof(s)));
338
339         CLEAR_global_sp;
340
341         return endsp;
342 #endif
343 }
344
345
346 Inst *builtin_throw(Inst *ip, java_objectheader *o, Cell *fp, Cell **new_spp, Cell **new_fpp)
347 {
348         classinfo      *c;
349         s4              framesize;
350         exceptionentry *ex;
351         s4              exceptiontablelength;
352         s4              i;
353
354   /* for a description of the stack see IRETURN in java.vmg */
355   for (; fp!=NULL;) {
356           functionptr f = codegen_findmethod((functionptr) (ip-1));
357
358           /* get methodinfo pointer from method header */
359           methodinfo *m = *(methodinfo **) (((u1 *) f) + MethodPointer);
360
361           framesize = (*((s4 *) (((u1 *) f) + FrameSize)));
362           ex = (exceptionentry *) (((u1 *) f) + ExTableStart);
363           exceptiontablelength = *((s4 *) (((u1 *) f) + ExTableSize));
364
365           builtin_trace_exception(o, m, ip, 1);
366
367           for (i = 0; i < exceptiontablelength; i++) {
368                   ex--;
369                   c = ex->catchtype;
370
371                   if (c != NULL) {
372                           if (!c->loaded)
373                                   /* XXX fix me! */
374                                   if (!load_class_bootstrap(c))
375                                           assert(0);
376
377                           if (!c->linked)
378                                   if (!link_class(c))
379                                           assert(0);
380                   }
381
382                   if (ip-1 >= (Inst *) ex->startpc && ip-1 < (Inst *) ex->endpc &&
383                           (c == NULL || builtin_instanceof(o, c))) {
384                           *new_spp = (Cell *)(((u1 *)fp) - framesize - SIZEOF_VOID_P);
385                           *new_fpp = fp;
386                           return (Inst *) (ex->handlerpc);
387                   }
388           }
389
390           ip = (Inst *)access_local_cell(-framesize - SIZEOF_VOID_P);
391           fp = (Cell *)access_local_cell(-framesize);
392   }
393
394   return NULL; 
395 }
396
397
398 FILE *vm_out = NULL;
399
400 #ifdef VM_DEBUG
401 #define NAME(_x) if (vm_debug) {fprintf(vm_out, "%lx: %-20s, ", (long)(ip-1), _x); fprintf(vm_out,"fp=%p, sp=%p", fp, sp);}
402 #else
403 #define NAME(_x)
404 #endif
405
406 #define LABEL(_inst) I_##_inst:
407 #define INST_ADDR(_inst) (&&I_##_inst)
408 #define LABEL2(_inst)
409
410
411 java_objectheader *
412 engine(Inst *ip0, Cell * sp, Cell * fp)
413 {
414   Inst * ip;
415   IF_spTOS(Cell   spTOS);
416   static Inst   labels[] = {
417 #include "java-labels.i"
418   };
419
420   if (vm_debug)
421       fprintf(vm_out,"entering engine(%p,%p,%p)\n",ip0,sp,fp);
422   if (ip0 == NULL) {
423     vm_prim = labels;
424     return NULL;
425   }
426
427   /* I don't have a clue where these things come from,
428      but I've put them in macros.h for the moment */
429   IF_spTOS(spTOS = sp[0]);
430
431   SET_IP(ip0);
432   NEXT;
433
434 #include "java-vm.i"
435 #undef NAME
436 }
437
438
439 /* true on success, false on exception */
440 static bool asm_calljavafunction_intern(methodinfo *m,
441                    void *arg1, void *arg2, void *arg3, void *arg4)
442 {
443   java_objectheader *retval;
444   Cell *sp = global_sp;
445   methoddesc *md;
446   functionptr entrypoint;
447
448   md = m->parseddesc;
449
450   CLEAR_global_sp;
451   assert(sp != NULL);
452
453   /* XXX ugly hack: thread's run() needs 5 arguments */
454   assert(md->paramcount < 6);
455
456   if (md->paramcount > 0)
457     *--sp=(Cell)arg1;
458   if (md->paramcount > 1)
459     *--sp=(Cell)arg2;
460   if (md->paramcount > 2)
461     *--sp=(Cell)arg3;
462   if (md->paramcount > 3)
463     *--sp=(Cell)arg4;
464   if (md->paramcount > 4)
465     *--sp=(Cell) 0;
466
467   entrypoint = createcalljavafunction(m);
468
469   retval = engine((Inst *) entrypoint, sp, NULL);
470
471   /* XXX remove the method from the method table */
472
473   if (retval != NULL) {
474           (void)builtin_throw_exception(retval);
475           return false;
476   }
477   else 
478           return true;
479 }
480
481 s4 asm_calljavafunction_int(methodinfo *m,
482                    void *arg1, void *arg2, void *arg3, void *arg4)
483 {
484         assert(m->parseddesc->returntype.type == TYPE_INT);
485         if (asm_calljavafunction_intern(m, arg1, arg2, arg3, arg4))
486                 return (s4)(*global_sp++);
487         else
488                 return 0;
489 }
490
491 java_objectheader *asm_calljavafunction(methodinfo *m,
492                    void *arg1, void *arg2, void *arg3, void *arg4)
493 {
494         if (asm_calljavafunction_intern(m, arg1, arg2, arg3, arg4)) {
495                 if (m->parseddesc->returntype.type == TYPE_ADR)
496                         return (java_objectheader *)(*global_sp++);
497                 else {
498                         assert(m->parseddesc->returntype.type == TYPE_VOID);
499                         return NULL;
500                 }
501         } else
502                 return NULL;
503 }
504
505 /* true on success, false on exception */
506 static bool jni_invoke_java_intern(methodinfo *m, u4 count, u4 size,
507                                           jni_callblock *callblock)
508 {
509         java_objectheader *retval;
510         Cell *sp = global_sp;
511         s4 i;
512         functionptr entrypoint;
513
514         CLEAR_global_sp;
515         assert(sp != NULL);
516
517         for (i = 0; i < count; i++) {
518                 switch (callblock[i].itemtype) {
519                 case TYPE_INT:
520                 case TYPE_FLT:
521                 case TYPE_ADR:
522                         *(--sp) = callblock[i].item;
523                         break;
524                 case TYPE_LNG:
525                 case TYPE_DBL:
526                         sp -= 2;
527                         *((u8 *) sp) = callblock[i].item;
528                         break;
529                 }
530         }
531
532         entrypoint = createcalljavafunction(m);
533
534         retval = engine((Inst *) entrypoint, sp, NULL);
535
536         /* XXX remove the method from the method table */
537
538         if (retval != NULL) {
539                 (void)builtin_throw_exception(retval);
540                 return false;
541         }
542         else
543                 return true;
544 }
545
546 java_objectheader *asm_calljavafunction2(methodinfo *m, u4 count, u4 size,
547                                          jni_callblock *callblock)
548 {
549   java_objectheader *retval = NULL;
550   if (jni_invoke_java_intern(m, count, size, callblock)) {
551           if (m->parseddesc->returntype.type == TYPE_ADR)
552                   retval = (java_objectheader *)*global_sp++;
553           else
554                   assert(m->parseddesc->returntype.type == TYPE_VOID);
555           return retval;
556   } else
557           return NULL;
558 }
559
560 s4 asm_calljavafunction2int(methodinfo *m, u4 count, u4 size,
561                             jni_callblock *callblock)
562 {
563   s4 retval=0;
564
565   if (jni_invoke_java_intern(m, count, size, callblock)) {
566           if (m->parseddesc->returntype.type == TYPE_INT)
567                   retval = *global_sp++;
568           else
569                   assert(m->parseddesc->returntype.type == TYPE_VOID);
570           return retval;
571   } else
572           return 0;
573 }
574
575 s8 asm_calljavafunction2long(methodinfo *m, u4 count, u4 size,
576                              jni_callblock *callblock)
577 {
578   s8 retval;
579   assert(m->parseddesc->returntype.type == TYPE_LNG);
580   if (jni_invoke_java_intern(m, count, size, callblock)) {
581           retval = *(s8 *)global_sp;
582           global_sp += 2;
583           return retval;
584   } else
585           return 0;
586 }
587
588 float asm_calljavafunction2float(methodinfo *m, u4 count, u4 size,
589                                          jni_callblock *callblock)
590 {
591   float retval;
592   assert(m->parseddesc->returntype.type == TYPE_FLT);
593   if (jni_invoke_java_intern(m, count, size, callblock)) {
594           retval = *(float *)global_sp;
595           global_sp += 1;
596           return retval;
597   } else
598           return 0.0;
599 }
600
601 double asm_calljavafunction2double(methodinfo *m, u4 count, u4 size,
602                                    jni_callblock *callblock)
603 {
604   double retval;
605   assert(m->parseddesc->returntype.type == TYPE_DBL);
606   if (jni_invoke_java_intern(m, count, size, callblock)) {
607           retval = *(double *)global_sp;
608           global_sp += 2;
609           return retval;
610   } else
611           return 0.0;
612 }
613
614 /*
615  * These are local overrides for various environment variables in Emacs.
616  * Please do not remove this and leave it at the end of the file, where
617  * Emacs will automagically detect them.
618  * ---------------------------------------------------------------------
619  * Local variables:
620  * mode: c
621  * indent-tabs-mode: t
622  * c-basic-offset: 4
623  * tab-width: 4
624  * End:
625  */