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