merge
[mono.git] / mono / arch / hppa / tramp.c
1 /*
2     Copyright (c) 2003 Bernie Solomon <bernard@ugsolutions.com>
3     
4     Permission is hereby granted, free of charge, to any person obtaining
5     a copy of this software and associated documentation files (the
6     "Software"), to deal in the Software without restriction, including
7     without limitation the rights to use, copy, modify, merge, publish,
8     distribute, sublicense, and/or sell copies of the Software, and to
9     permit persons to whom the Software is furnished to do so, subject to
10     the following conditions:
11     
12     The above copyright notice and this permission notice shall be
13     included in all copies or substantial portions of the Software.
14     
15     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19     LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20     OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23
24     Trampoline generation for HPPA - currently (Oct 9th 2003) only
25     supports 64 bits - and the HP compiler.
26 */
27 #ifndef __linux__
28
29 #include "mono/interpreter/interp.h"
30 #include "mono/metadata/appdomain.h"
31 #include "mono/metadata/tabledefs.h"
32 #include "hppa-codegen.h"
33
34 #if SIZEOF_VOID_P != 8
35 #error "HPPA code only currently supports 64bit pointers"
36 #endif
37
38 // debugging flag which dumps code generated 
39 static int debug_asm = 0;
40
41
42 static void flush_cache(void *address, int length)
43 {
44 #ifdef __GNUC__
45 #error "currently only supports the HP C compiler"
46 #else
47         int cache_line_size = 16;
48         ulong_t end = (ulong_t)address + length;
49         register ulong_t sid;
50         register ulong_t offset = (ulong_t) address;
51         register ulong_t r0 = 0;
52
53         _asm("LDSID", 0, offset, sid);
54         _asm("MTSP", sid, 0);
55         _asm("FDC", r0, 0, offset);
56         offset = (offset + (cache_line_size - 1)) & ~(cache_line_size - 1);
57         while (offset < end) {
58                 (void)_asm("FDC", r0, 0, offset);
59                 offset += cache_line_size;
60         }
61         _asm("SYNC");
62         offset = (ulong_t) address;
63         _asm("FIC", r0, 0, offset);
64         offset = (offset + (cache_line_size - 1)) & ~(cache_line_size - 1);
65         while (offset < end) {
66                 (void)_asm("FIC", r0, 0, offset);
67                 offset += cache_line_size;
68         }
69         _asm("SYNC");
70         // sync needs at least 7 instructions after it... this is what is used for NOP
71         _asm("OR", 0, 0, 0);
72         _asm("OR", 0, 0, 0);
73         _asm("OR", 0, 0, 0);
74         _asm("OR", 0, 0, 0);
75         _asm("OR", 0, 0, 0);
76         _asm("OR", 0, 0, 0);
77         _asm("OR", 0, 0, 0);
78 #endif
79 }
80
81 static void disassemble (guint32 *code, int n_instrs)
82 {
83         const char *tmp_file = "/tmp/mono_adb.in";
84         FILE *fp = fopen(tmp_file, "w");
85         int i;
86         for (i = 0; i < n_instrs; i++)
87                 fprintf(fp, "0x%08x=i\n", code[i]);
88         fprintf(fp, "$q\n");
89         fclose(fp);
90         system("adb64 </tmp/mono_adb.in");
91         unlink(tmp_file);
92 }
93
94 #define ADD_INST(code, pc, gen_exp) \
95         do { if ((code) == NULL) (pc)++; else { gen_exp; pc++; } } while (0)
96
97 /*
98  * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
99  */
100
101 MonoPIFunc
102 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
103 {
104         int pc, save_pc;
105         int param;
106         void **descriptor;
107         unsigned int *code = NULL;
108         unsigned int *code_start = NULL;
109         int arg_reg;
110 #define FP_ARG_REG(r) (4 + (26 - arg_reg))
111         int arg_offset;
112         int frame_size = 0;
113         int spill_offset;
114         int parameter_offset;
115         int parameter_slot;
116         int args_on_stack;
117
118         if (debug_asm) {
119                 fprintf(stderr, "trampoline: # params %d has this %d exp this %d string %d, ret type %d\n", 
120                         sig->param_count, sig->hasthis, sig->explicit_this, string_ctor, sig->ret->type);
121         }
122
123         // everything takes 8 bytes unless it is a bigger struct
124         for (param = 0; param < sig->param_count; param++) {
125                 if (sig->params[param]->byref)
126                         frame_size += 8;
127                 else {
128                         if (sig->params[param]->type != MONO_TYPE_VALUETYPE)
129                                 frame_size += 8;
130                         else {
131                                 if (sig->params [param]->data.klass->enumtype) 
132                                         frame_size += 8;
133                                 else {
134                                         frame_size += 15; // large structs are 16 byte aligned
135                                         frame_size &= ~15;
136                                         frame_size += mono_class_native_size (sig->params [param]->data.klass, NULL);
137                                         frame_size += 7;
138                                         frame_size &= ~7;
139                                 }
140                         }
141                 }
142         }
143                                 
144         if (sig->hasthis)
145                 frame_size += 8;
146         // 16 byte alignment
147         if ((frame_size & 15) != 0)
148                 frame_size += 8;
149         // minimum is 64 bytes
150         if (frame_size < 64)
151                 frame_size = 64;
152
153         if (debug_asm)
154                 fprintf(stderr, "outgoing frame size: %d\n", frame_size);
155
156         frame_size += 16; // for the frame marker (called routines stuff return address etc. here)
157         frame_size += 32; // spill area for r4, r5 and r27 (16 byte aligned)
158
159         spill_offset = -frame_size;
160         parameter_offset = spill_offset + 32; // spill area size is really 24
161         spill_offset += 8;
162
163         /* the rest executes twice - once to count instructions so we can
164            allocate memory in one block and once to fill it in... the count
165            should be pretty fast anyway...
166         */
167 generate:
168         pc = 0;
169         arg_reg = 26;
170         arg_offset = 0;
171         args_on_stack = 0;
172         parameter_slot = parameter_offset;
173
174         ADD_INST(code, pc, hppa_std(code, 2, -16, 30));  // STD   %r2,-16(%r30)   
175         ADD_INST(code, pc, hppa_std_ma(code, 3, frame_size, 30));
176         ADD_INST(code, pc, hppa_std(code, 4, spill_offset, 30));
177         ADD_INST(code, pc, hppa_std(code, 5, spill_offset + 8, 30));
178         ADD_INST(code, pc, hppa_copy(code, 29, 3));        // COPY        %r29,%r3                
179         ADD_INST(code, pc, hppa_std(code, 27, spill_offset + 16, 30));
180         ADD_INST(code, pc, hppa_nop(code));                // NOP                         
181
182         ADD_INST(code, pc, hppa_std(code, 26, -64, 29)); // STD   %r26,-64(%r29)  callme
183         ADD_INST(code, pc, hppa_std(code, 25, -56, 29)); // STD   %r25,-56(%r29)  retval
184         ADD_INST(code, pc, hppa_std(code, 24, -48, 29)); // STD   %r24,-48(%r29)  this_obj
185         ADD_INST(code, pc, hppa_std(code, 23, -40, 29)); // STD   %r23,-40(%r29)  arguments
186
187         if (sig->param_count > 0)
188                 ADD_INST(code, pc, hppa_copy(code, 23, 4));  // r4 is the current pointer to the stackval array of args
189
190         if (sig->hasthis) {
191                 if (sig->call_convention != MONO_CALL_THISCALL) {
192                         ADD_INST(code, pc, hppa_copy(code, 24, arg_reg));
193                         --arg_reg;
194                         parameter_slot += 8;
195                 } else  {
196                         fprintf(stderr, "case I didn't handle\n");
197                 }
198         }
199
200         for (param = 0; param < sig->param_count; param++) {
201                 int type = sig->params[param]->type;
202                 if (sig->params[param]->byref) {
203                         if (args_on_stack) {
204                                 ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, 5));
205                                 ADD_INST(code, pc, hppa_std(code, 5, parameter_slot, 30));
206                         } else {
207                                 ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, arg_reg));
208                                 --arg_reg;
209                         }
210                         arg_offset += sizeof(stackval);
211                         parameter_slot += 8;
212                         continue;
213                 }
214         typeswitch:
215                 switch (type) {
216                 case MONO_TYPE_CHAR:
217                 case MONO_TYPE_BOOLEAN:
218                 case MONO_TYPE_I1:
219                 case MONO_TYPE_U1:
220                 case MONO_TYPE_I2:
221                 case MONO_TYPE_U2:
222                 case MONO_TYPE_I4:
223                 case MONO_TYPE_U4:
224                         if (args_on_stack) {
225                                 ADD_INST(code, pc, hppa_ldw(code, arg_offset, 4, 5));
226                                 switch (type) {
227                                 case MONO_TYPE_I4:
228                                 case MONO_TYPE_U4:
229                                         ADD_INST(code, pc, hppa_stw(code, 5, parameter_slot + 4, 30));
230                                         break;
231                                 case MONO_TYPE_CHAR:
232                                 case MONO_TYPE_I2:
233                                 case MONO_TYPE_U2:
234                                         ADD_INST(code, pc, hppa_sth(code, 5, parameter_slot + 6, 30));
235                                         break;
236                                 case MONO_TYPE_BOOLEAN:
237                                 case MONO_TYPE_I1:
238                                 case MONO_TYPE_U1:
239                                         ADD_INST(code, pc, hppa_stb(code, 5, parameter_slot + 7, 30));
240                                         break;
241                                 }
242                         } else {
243                                 ADD_INST(code, pc, hppa_ldw(code, arg_offset, 4, arg_reg));
244                                 --arg_reg;
245                         }
246                         arg_offset += sizeof(stackval);
247                         parameter_slot += 8;
248                         break;
249                 case MONO_TYPE_I8:
250                 case MONO_TYPE_U8:
251                 case MONO_TYPE_I:
252                 case MONO_TYPE_U:
253                 case MONO_TYPE_STRING:
254                 case MONO_TYPE_OBJECT:
255                 case MONO_TYPE_CLASS:
256                 case MONO_TYPE_SZARRAY:
257                 case MONO_TYPE_PTR:
258                         if (args_on_stack) {
259                                 ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, 5));
260                                 ADD_INST(code, pc, hppa_std(code, 5, parameter_slot, 30));
261                         } else {
262                                 ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, arg_reg));
263                                 --arg_reg;
264                         }
265                         arg_offset += sizeof(stackval);
266                         parameter_slot += 8;
267                         break;
268                 case MONO_TYPE_R8:
269                         if (args_on_stack) {
270                                 ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, 5));
271                                 ADD_INST(code, pc, hppa_std(code, 5, parameter_slot, 30));
272                         } else {
273                                 ADD_INST(code, pc, hppa_fldd(code, arg_offset, 4, FP_ARG_REG(arg_reg)));
274                                 --arg_reg;
275                         }
276                         arg_offset += sizeof(stackval);
277                         parameter_slot += 8;
278                         break;
279                 case MONO_TYPE_R4:
280                         if (args_on_stack) {
281                                 ADD_INST(code, pc, hppa_fldd(code, arg_offset, 4, 22));
282                                 ADD_INST(code, pc, hppa_fcnv_dbl_sng(code, 22, 22));
283                                 ADD_INST(code, pc, hppa_fstw(code, 22, parameter_slot + 4, 30));
284                         } else {
285                                 ADD_INST(code, pc, hppa_fldd(code, arg_offset, 4, FP_ARG_REG(arg_reg)));
286                                 ADD_INST(code, pc, hppa_fcnv_dbl_sng(code, FP_ARG_REG(arg_reg), FP_ARG_REG(arg_reg)));
287                                 --arg_reg;
288                         }
289                         arg_offset += sizeof(stackval);
290                         parameter_slot += 8;
291                         break;
292                 case MONO_TYPE_VALUETYPE:
293                         if (sig->params [param]->data.klass->enumtype) {
294                                 type = sig->params [param]->data.klass->enum_basetype->type;
295                                 goto typeswitch;
296                         } else {
297                                 int size = mono_class_native_size (sig->params [param]->data.klass, NULL);
298                                 // assumes struct is 8 byte aligned whatever its size... (as interp.c guarantees at present)
299                                 // copies multiple of 8 bytes which may include some trailing garbage but should be safe
300                                 if (size <= 8) {
301                                         if (args_on_stack) {
302                                                 ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, 5));
303                                                 ADD_INST(code, pc, hppa_ldd(code, 0, 5, 5));
304                                                 ADD_INST(code, pc, hppa_std(code, 5, parameter_slot, 30));
305                                         } else {
306                                                 ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, arg_reg));
307                                                 ADD_INST(code, pc, hppa_ldd(code, 0, arg_reg, arg_reg));
308                                                 --arg_reg;
309                                         }
310                                         parameter_slot += 8;
311                                 } else {
312                                         int soffset = 0;
313                                         if ((parameter_slot & 15) != 0) {
314                                                 --arg_reg;
315                                                 if (arg_reg < 19) {
316                                                         args_on_stack = 1;
317                                                 }
318                                                 parameter_slot += 8;
319                                         }
320                                         ADD_INST(code, pc, hppa_ldd(code, arg_offset, 4, 5));
321                                         // might generate a lot of code for very large structs... should
322                                         // use a loop or routine call them
323                                         while (size > 0) {
324                                                 if (args_on_stack) {
325                                                         ADD_INST(code, pc, hppa_ldd(code, soffset, 5, 31));
326                                                         ADD_INST(code, pc, hppa_std(code, 31, parameter_slot, 30));
327                                                 } else {
328                                                         ADD_INST(code, pc, hppa_ldd(code, soffset, 5, arg_reg));
329                                                         --arg_reg;
330                                                         if (arg_reg < 19)
331                                                                 args_on_stack = 1;
332                                                 }
333                                                 parameter_slot += 8;
334                                                 soffset += 8;
335                                                 size -= 8;
336                                         }
337                                 }
338                                 arg_offset += sizeof(stackval);
339                                 break;
340                         }
341                         break;
342                 default:
343                         g_error ("mono_create_trampoline: unhandled arg type %d", type);
344                         return NULL;
345                 }
346
347                 if (arg_reg < 19) {
348                         args_on_stack = 1;
349                 }
350         }
351
352         // for large return structs just pass on the buffer given to us.
353         if (sig->ret->type == MONO_TYPE_VALUETYPE && sig->ret->data.klass->enumtype == 0) {
354                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
355                 if (size > 16) {
356                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 28));
357                         ADD_INST(code, pc, hppa_ldd(code, 0, 28, 28));
358                 }
359         }
360
361         ADD_INST(code, pc, hppa_nop(code));                // NOP                         
362         ADD_INST(code, pc, hppa_ldd(code, -64, 29, 5));
363         ADD_INST(code, pc, hppa_ldd(code, 24, 5, 27));
364         ADD_INST(code, pc, hppa_ldd(code, 16, 5, 5));
365         ADD_INST(code, pc, hppa_blve(code, 5));
366         ADD_INST(code, pc, hppa_ldo(code, parameter_offset + 64, 30, 29));
367         ADD_INST(code, pc, hppa_ldd(code, spill_offset + 16, 30, 27));
368         ADD_INST(code, pc, hppa_nop(code));                // NOP                         
369         
370         if (string_ctor) {
371                 ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19)); // LDD   -56(%r3),%r19   
372                 ADD_INST(code, pc, hppa_std(code, 28, 0, 19));  // STD   %r28,0(%r19)    
373         }
374         else if (sig->ret->type != MONO_TYPE_VOID) {
375                 int type = sig->ret->type;
376
377         rettypeswitch:
378                 switch (type) {
379                 case MONO_TYPE_BOOLEAN:
380                 case MONO_TYPE_I1:
381                 case MONO_TYPE_U1:
382                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19)); // LDD   -56(%r3),%r19   
383                         ADD_INST(code, pc, hppa_stb(code, 28, 0, 19));  // STB   %r28,0(%r19)    
384                         break;
385                 case MONO_TYPE_I4:
386                 case MONO_TYPE_U4:
387                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19)); // LDD   -56(%r3),%r19   
388                         ADD_INST(code, pc, hppa_stw(code, 28, 0, 19));  // STW   %r28,0(%r19)    
389                         break;
390                 case MONO_TYPE_CHAR:
391                 case MONO_TYPE_I2:
392                 case MONO_TYPE_U2:
393                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19)); // LDD   -56(%r3),%r19   
394                         ADD_INST(code, pc, hppa_sth(code, 28, 0, 19));  // STH   %r28,0(%r19)
395                         break;
396                 case MONO_TYPE_I8:
397                 case MONO_TYPE_U8:
398                 case MONO_TYPE_I:
399                 case MONO_TYPE_U:
400                 case MONO_TYPE_STRING:
401                 case MONO_TYPE_OBJECT:
402                 case MONO_TYPE_CLASS:
403                 case MONO_TYPE_SZARRAY:
404                 case MONO_TYPE_PTR:
405                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19)); // LDD   -56(%r3),%r19   
406                         ADD_INST(code, pc, hppa_std(code, 28, 0, 19));  // STD   %r28,0(%r19)    
407                         break;
408                 case MONO_TYPE_R8:
409                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19)); // LDD   -56(%r3),%r19   
410                         ADD_INST(code, pc, hppa_fstd(code, 4, 0, 19));  // FSTD   %fr4,0(%r19)    
411                         break;
412                 case MONO_TYPE_R4:
413                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19)); // LDD   -56(%r3),%r19   
414                         ADD_INST(code, pc, hppa_fstw(code, 4, 0, 19));  // FSTW   %fr4r,0(%r19)    
415                         break;
416                 case MONO_TYPE_VALUETYPE:
417                         if (sig->ret->data.klass->enumtype) {
418                                 type = sig->ret->data.klass->enum_basetype->type;
419                                 goto rettypeswitch;
420                         } else {
421                                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
422                                 if (size <= 16) {
423                                         int reg = 28;
424                                         int off = 0;
425                                         ADD_INST(code, pc, hppa_ldd(code, -56, 3, 19));
426                                         ADD_INST(code, pc, hppa_ldd(code, 0, 19, 19));
427                                         if (size > 8) {
428                                                 ADD_INST(code, pc, hppa_std(code, 28, 0, 19)); 
429                                                 size -= 8;
430                                                 reg = 29;
431                                                 off += 8;
432                                         }
433                                         // get rest of value right aligned in the register
434                                         ADD_INST(code, pc, hppa_extrdu(code, reg, 8 * size - 1, 8 * size, reg));
435                                         if ((size & 1) != 0) {
436                                                 ADD_INST(code, pc, hppa_stb(code, reg, off + size - 1, 19));
437                                                 ADD_INST(code, pc, hppa_extrdu(code, reg, 55, 56, reg));
438                                                 size -= 1;
439                                         }
440                                         if ((size & 2) != 0) {
441                                                 ADD_INST(code, pc, hppa_sth(code, reg, off + size - 2, 19));
442                                                 ADD_INST(code, pc, hppa_extrdu(code, reg, 47, 48, reg));
443                                                 size -= 2;
444                                         }
445                                         if ((size & 4) != 0)
446                                                 ADD_INST(code, pc, hppa_stw(code, reg, off + size - 4, 19));
447                                 }
448                                 break;
449                         }
450                 default:
451                         g_error ("mono_create_trampoline: unhandled ret type %d", type);
452                         return NULL;
453                 }
454         }
455
456         ADD_INST(code, pc, hppa_ldd(code, -frame_size-16, 30, 2));
457         ADD_INST(code, pc, hppa_ldd(code, spill_offset, 30, 4));
458         ADD_INST(code, pc, hppa_ldd(code, spill_offset + 8, 30, 5));
459         ADD_INST(code, pc, hppa_bve(code, 2, 0));
460         ADD_INST(code, pc, hppa_ldd_mb(code, -frame_size, 30, 3));
461
462         if (code == NULL) {
463                 descriptor = (void **)g_malloc(4 * sizeof(void *) + pc * sizeof(unsigned int));
464                 code = (unsigned int *)((char *)descriptor + 4 * sizeof(void *));
465                 code_start = code;
466                 save_pc = pc;
467                 goto generate;
468         } else 
469                 g_assert(pc == save_pc);
470
471         if (debug_asm) {
472                 fprintf(stderr, "generated: %d bytes\n", pc * 4);
473                 disassemble(code_start, pc);
474         }
475
476         // must do this so we can actually execute the code we just put in memory
477         flush_cache(code_start, 4 * pc);
478
479         descriptor[0] = 0;
480         descriptor[1] = 0;
481         descriptor[2] = code_start;
482         descriptor[3] = 0;
483
484         return (MonoPIFunc)descriptor;
485 }
486
487 void *
488 mono_arch_create_method_pointer (MonoMethod *method)
489 {
490         MonoMethodSignature *sig = method->signature;
491         MonoJitInfo *ji;
492         int i;
493         int pc;
494         int param;
495         void **descriptor = NULL;
496         void **data = NULL;
497         unsigned int *code = NULL;
498         unsigned int *code_start = NULL;
499         int arg_reg = 26;
500         int arg_offset = 0;
501         int frame_size;
502         int invoke_rec_offset;
503         int stack_vals_offset;
504         int stack_val_pos;
505         int arg_val_pos;
506         int spill_offset;
507         int *vtoffsets;
508         int t;
509
510         if (debug_asm) {
511                 fprintf(stderr, "mono_create_method_pointer %s: flags %d\n", method->name, method->flags);
512                 fprintf(stderr, "method: # params %d has this %d exp this %d\n", sig->param_count, sig->hasthis, sig->explicit_this);
513                 fprintf(stderr, "ret %d\n", sig->ret->type);
514                 for (i = 0; i < sig->param_count; i++)
515                         fprintf(stderr, "%d: %d\n", i, sig->params[i]->type);
516         }
517
518         // the extra stackval is for the return val if necessary
519         // the 64 is for outgoing parameters and the 16 is the frame marker.
520         // the other 16 is space for struct return vals < 16 bytes
521         frame_size = sizeof(MonoInvocation) + (sig->param_count + 1) * sizeof(stackval) + 16 + 64 + 16;
522         frame_size += 15;
523         frame_size &= ~15;
524         invoke_rec_offset = -frame_size;
525         vtoffsets = (int *)alloca(sig->param_count * sizeof(int));
526
527         t = invoke_rec_offset;
528
529         for (i = 0; i < sig->param_count; ++i)
530                 if (sig->params[i]->type == MONO_TYPE_VALUETYPE &&
531                     !sig->params[i]->data.klass->enumtype && !sig->params[i]->byref) {
532                         int size = mono_class_native_size (sig->params[i]->data.klass, NULL);
533                         size += 7;
534                         size &= ~7;
535                         t -= size;
536                         frame_size += size;
537                         vtoffsets[i] = t;
538                 }
539
540         stack_vals_offset = invoke_rec_offset + sizeof(MonoInvocation);
541         stack_vals_offset += 7;
542         stack_vals_offset &= ~7;
543         frame_size += 32;
544         frame_size += 15;
545         frame_size &= ~15;
546         spill_offset = -frame_size + 8;
547
548 generate:
549         stack_val_pos = stack_vals_offset;
550         arg_val_pos = -64;
551         pc = 0;
552
553         ADD_INST(code, pc, hppa_std(code, 2, -16, 30));
554         ADD_INST(code, pc, hppa_std_ma(code, 3, frame_size, 30));
555         ADD_INST(code, pc, hppa_std(code, 4, spill_offset, 30));
556         ADD_INST(code, pc, hppa_copy(code, 29, 3));
557         ADD_INST(code, pc, hppa_std(code, 27, spill_offset + 8, 30));
558         ADD_INST(code, pc, hppa_std(code, 28, spill_offset + 16, 30));
559         ADD_INST(code, pc, hppa_nop(code));
560
561         ADD_INST(code, pc, hppa_std(code, 26, -64, 29)); // STD   %r26,-64(%r29)
562         ADD_INST(code, pc, hppa_std(code, 25, -56, 29)); // STD   %r25,-56(%r29)
563         ADD_INST(code, pc, hppa_std(code, 24, -48, 29)); // STD   %r24,-48(%r29)
564         ADD_INST(code, pc, hppa_std(code, 23, -40, 29)); // STD   %r23,-40(%r29)
565         ADD_INST(code, pc, hppa_std(code, 22, -32, 29)); // STD   %r22,-32(%r29)
566         ADD_INST(code, pc, hppa_std(code, 21, -24, 29)); // STD   %r21,-24(%r29)
567         ADD_INST(code, pc, hppa_std(code, 20, -16, 29)); // STD   %r20,-16(%r29)
568         ADD_INST(code, pc, hppa_std(code, 19, -8, 29));  // STD   %r19,-8(%r29)
569
570         ADD_INST(code, pc, hppa_std(code, 0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, parent), 30));
571         ADD_INST(code, pc, hppa_std(code, 0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, ex), 30));
572         ADD_INST(code, pc, hppa_std(code, 0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, ex_handler), 30));
573         ADD_INST(code, pc, hppa_std(code, 0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, ip), 30));
574
575         if (data != NULL)
576                 data[0] = method;
577         ADD_INST(code, pc, hppa_ldd(code, 0, 27, 19));
578         ADD_INST(code, pc, hppa_std(code, 19, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, method), 30));
579
580         if (sig->hasthis) {
581                 if (sig->call_convention != MONO_CALL_THISCALL) {
582                         ADD_INST(code, pc, hppa_std(code, arg_reg, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, obj), 30));
583                         arg_val_pos += 8;
584                 } else {
585                         fprintf(stderr, "case I didn't handle 2\n");
586                 }
587         }
588
589         if (data != NULL)
590                 data[2] = (void *)stackval_from_data;
591
592         for (i = 0; i < sig->param_count; ++i) {
593                 if (data != NULL)
594                         data[4 + i] = sig->params[i];
595                 ADD_INST(code, pc, hppa_ldd(code, (4 + i) * 8, 27, 26)); // LDD   x(%r27),%r26 == type
596                 ADD_INST(code, pc, hppa_ldo(code, stack_val_pos, 30, 25)); // LDD       x(%r30),%r25 == &stackval
597                 if (sig->params[i]->byref) {
598                         ADD_INST(code, pc, hppa_ldo(code, arg_val_pos, 3, 24));
599                 } else {
600                         int type = sig->params[i]->type;
601                 typeswitch:
602                         switch (type) {
603                         case MONO_TYPE_I8:
604                         case MONO_TYPE_U8:
605                         case MONO_TYPE_I:
606                         case MONO_TYPE_U:
607                         case MONO_TYPE_STRING:
608                         case MONO_TYPE_OBJECT:
609                         case MONO_TYPE_CLASS:
610                         case MONO_TYPE_SZARRAY:
611                         case MONO_TYPE_PTR:
612                         case MONO_TYPE_R8:
613                                 ADD_INST(code, pc, hppa_ldo(code, arg_val_pos, 3, 24));
614                                 break;
615                         case MONO_TYPE_I4:
616                         case MONO_TYPE_U4:
617                                 ADD_INST(code, pc, hppa_ldo(code, arg_val_pos + 4, 3, 24));
618                                 break;
619                         case MONO_TYPE_CHAR:
620                         case MONO_TYPE_I2:
621                         case MONO_TYPE_U2:
622                                 ADD_INST(code, pc, hppa_ldo(code, arg_val_pos + 6, 3, 24));
623                                 break;
624                         case MONO_TYPE_I1:
625                         case MONO_TYPE_U1:
626                         case MONO_TYPE_BOOLEAN:
627                                 ADD_INST(code, pc, hppa_ldo(code, arg_val_pos + 7, 3, 24));
628                                 break;
629                         case MONO_TYPE_VALUETYPE:
630                                 if (sig->params [i]->data.klass->enumtype) {
631                                         type = sig->params [i]->data.klass->enum_basetype->type;
632                                         goto typeswitch;
633                                 } else {
634                                         int size = mono_class_native_size (sig->params[i]->data.klass, NULL);
635                                         if (size <= 8)
636                                                 ADD_INST(code, pc, hppa_ldo(code, arg_val_pos, 3, 24));
637                                         else {
638                                                 arg_val_pos += 15;
639                                                 arg_val_pos &= ~15;
640                                                 ADD_INST(code, pc, hppa_ldo(code, arg_val_pos, 3, 24));
641                                         }
642
643                                         arg_val_pos += size;
644                                         arg_val_pos += 7;
645                                         arg_val_pos &= ~7;
646                                         arg_val_pos -=8 ; // as it is incremented later
647
648                                         ADD_INST(code, pc, hppa_ldo(code, vtoffsets[i], 30, 19));
649                                         ADD_INST(code, pc, hppa_std(code, 19, 0, 25));
650                                 }
651                                 break;
652                         default:
653                                 fprintf(stderr, "can not cope in create method pointer %d\n", sig->params[i]->type);
654                                 break;
655                         }
656                 }
657
658                 ADD_INST(code, pc, hppa_ldo(code, sig->pinvoke, 0, 23)); // LDI sig->pinvoke,%r23
659                 ADD_INST(code, pc, hppa_ldd(code, 16, 27, 19)); // LDD     x(%r27),%r19 == stackval_from_data
660                 ADD_INST(code, pc, hppa_ldd(code, 16, 19, 20)); // LDD     16(%r19),%r20   
661                 ADD_INST(code, pc, hppa_ldd(code, 24, 19, 27)); // LDD     24(%r19),%r27   
662                 ADD_INST(code, pc, hppa_blve(code, 20));                // BVE,L   (%r20),%r2      
663                 ADD_INST(code, pc, hppa_ldo(code, -16, 30, 29));        // LDO     -16(%r30),%r29
664                 ADD_INST(code, pc, hppa_ldd(code, spill_offset + 8, 30, 27));
665
666                 stack_val_pos += sizeof (stackval);
667                 arg_val_pos += 8;
668                 g_assert(stack_val_pos < -96);
669         }
670         
671         ADD_INST(code, pc, hppa_ldo(code, stack_vals_offset, 30, 19));
672         ADD_INST(code, pc, hppa_std(code, 19, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, stack_args), 30));
673         ADD_INST(code, pc, hppa_ldo(code, stack_val_pos, 30, 19));
674         ADD_INST(code, pc, hppa_std(code, 19, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, retval), 30));
675
676         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype) {
677                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
678                 // for large return structs pass on the pointer given us by our caller.
679                 if (size > 16)
680                         ADD_INST(code, pc, hppa_ldd(code, spill_offset + 16, 30, 28));
681                 else // use space left on stack for the return value
682                         ADD_INST(code, pc, hppa_ldo(code, stack_val_pos + sizeof(stackval), 30, 28));
683                 ADD_INST(code, pc, hppa_std(code, 28, stack_val_pos, 30));
684         }
685
686         ADD_INST(code, pc, hppa_ldo(code, invoke_rec_offset, 30, 26)); // address of invocation
687
688         if (data != NULL)
689                 data[1] = (void *)ves_exec_method;
690         ADD_INST(code, pc, hppa_ldd(code, 8, 27, 19));  // LDD     8(%r27),%r19
691         ADD_INST(code, pc, hppa_ldd(code, 16, 19, 20)); // LDD     16(%r19),%r20   
692         ADD_INST(code, pc, hppa_ldd(code, 24, 19, 27)); // LDD     24(%r19),%r27   
693         ADD_INST(code, pc, hppa_blve(code, 20));                // BVE,L   (%r20),%r2      
694         ADD_INST(code, pc, hppa_ldo(code, -16, 30, 29));        // LDO     -16(%r30),%r29
695         ADD_INST(code, pc, hppa_ldd(code, spill_offset + 8, 30, 27));
696         if (sig->ret->byref) {
697                 fprintf(stderr, "can'ty cope with ret byref\n");
698         } else {
699                 int simpletype = sig->ret->type;        
700         enum_retvalue:
701                 switch (simpletype) {
702                 case MONO_TYPE_VOID:
703                         break;
704                 case MONO_TYPE_BOOLEAN:
705                 case MONO_TYPE_I1:
706                 case MONO_TYPE_U1:
707                 case MONO_TYPE_CHAR:
708                 case MONO_TYPE_I2:
709                 case MONO_TYPE_U2:
710                 case MONO_TYPE_I4:
711                 case MONO_TYPE_U4:
712                         ADD_INST(code, pc, hppa_ldw(code, stack_val_pos, 30, 28)); // LDW       x(%r30),%r28
713                         break;
714                 case MONO_TYPE_I8:
715                 case MONO_TYPE_U8:
716                 case MONO_TYPE_I:
717                 case MONO_TYPE_U:
718                 case MONO_TYPE_STRING:
719                 case MONO_TYPE_OBJECT:
720                 case MONO_TYPE_CLASS:
721                 case MONO_TYPE_SZARRAY:
722                 case MONO_TYPE_PTR:
723                         ADD_INST(code, pc, hppa_ldd(code, stack_val_pos, 30, 28)); // LDD       x(%r30),%r28
724                         break;
725                 case MONO_TYPE_R8:
726                         ADD_INST(code, pc, hppa_fldd(code, stack_val_pos, 30, 4)); // FLDD       x(%r30),%fr4
727                         break;
728                 case MONO_TYPE_VALUETYPE:
729                         if (sig->ret->data.klass->enumtype) {
730                                 simpletype = sig->ret->data.klass->enum_basetype->type;
731                                 goto enum_retvalue;
732                         } else {
733                                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
734                                 if (size <= 16) {
735                                         ADD_INST(code, pc, hppa_ldd(code, stack_val_pos, 30, 28));
736                                         if (size > 8)
737                                                 ADD_INST(code, pc, hppa_ldd(code, 8, 28, 29)); 
738                                         ADD_INST(code, pc, hppa_ldd(code, 0, 28, 28)); 
739                                 }
740                         }
741                         break;
742                 default:
743                         fprintf(stderr, "can't cope with ret type %d\n", simpletype);
744                         return NULL;
745                 }
746         }
747
748         ADD_INST(code, pc, hppa_ldd(code, -frame_size-16, 30, 2));
749         ADD_INST(code, pc, hppa_ldd(code, spill_offset, 30, 4));
750         ADD_INST(code, pc, hppa_bve(code, 2, 0));
751         ADD_INST(code, pc, hppa_ldd_mb(code, -frame_size, 30, 3));
752         if (code == NULL) {
753                 descriptor = (void **)malloc((8 + sig->param_count) * sizeof(void *) + sizeof(unsigned int) * pc);
754                 data = descriptor + 4;
755                 code = (unsigned int *)(data + 4 + sig->param_count);
756                 code_start = code;
757                 goto generate;
758         }
759
760         if (debug_asm) {
761                 fprintf(stderr, "generated: %d bytes\n", pc * 4);
762                 disassemble(code_start, pc);
763         }
764
765         flush_cache(code_start, 4 * pc);
766
767         descriptor[0] = 0;
768         descriptor[1] = 0;
769         descriptor[2] = code_start;
770         descriptor[3] = data;
771
772         ji = g_new0 (MonoJitInfo, 1);
773         ji->method = method;
774         ji->code_size = 4; // does this matter?
775         ji->code_start = descriptor;
776
777         mono_jit_info_table_add (mono_get_root_domain (), ji);
778
779         return ji->code_start;
780 }
781 #endif