2003-10-31 Zoltan Varga <vargaz@freemail.hu>
[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
31 #if SIZEOF_VOID_P != 8
32 #error "HPPA code only currently supports 64bit pointers"
33 #endif
34
35 // debugging flag which dumps code generated 
36 static int debug_asm = 0;
37
38 #define NOP 0x08000240
39
40 #define LDB(disp, base, dest, neg) (0x40000000 | (((disp) & 0x1fff) << 1) | ((base) << 21) | ((dest) << 16) | neg)
41 #define STB(src, disp, base, neg) (0x60000000 | (((disp) & 0x1fff) << 1) | ((base) << 21) | ((src) << 16) | neg)
42
43 #define LDH(disp, base, dest, neg) (0x44000000 | (((disp) & 0x1fff) << 1) | ((base) << 21) | ((dest) << 16) | neg)
44 #define STH(src, disp, base, neg) (0x64000000 | (((disp) & 0x1fff) << 1) | ((base) << 21) | ((src) << 16) | neg)
45
46 #define LDW(disp, base, dest, neg) (0x48000000 | (((disp) & 0x1fff) << 1) | ((base) << 21) | ((dest) << 16) | neg)
47 #define STW(src, disp, base, neg) (0x68000000 | (((disp) & 0x1fff) << 1) | ((base) << 21) | ((src) << 16) | neg)
48
49 #define COPY(src, dest)           (0x34000000 | ((src) << 21) | ((dest) << 16))
50 #define LDD(im10a, base, dest, m, a, neg) (0x50000000 | (((im10a) & 0x3ff) << 4) | ((base) << 21) | ((dest) << 16) | neg | (m ? 0x8 : 0) | (a ? 0x4 : 0))
51 #define STD(src, im10a, base, m , a, neg) (0x70000000 | (((im10a) & 0x3ff) << 4) | ((base) << 21) | ((src) << 16) | neg | (m ? 0x8 : 0) | (a ? 0x4 : 0))
52
53 #define FLDD(im10a, base, dest, m, a, neg) (0x50000002 | (((im10a) & 0x3ff) << 4) | ((base) << 21) | ((dest) << 16) | neg | (m ? 0x8 : 0) | (a ? 0x4 : 0))
54 #define FSTD(src, im10a, base, m , a, neg) (0x70000002 | (((im10a) & 0x3ff) << 4) | ((base) << 21) | ((src) << 16) | neg | (m ? 0x8 : 0) | (a ? 0x4 : 0))
55
56 #define FLDW(im11a, base, dest, r, neg) (0x5c000000 | (((im11a) & 0x7ff) << 3) | ((base) << 21) | ((dest) << 16) | neg | ((r) ? 0x2 : 0))
57 #define FSTW(src, im11a, base, r, neg) (0x7c000000 | (((im11a) & 0x7ff) << 3) | ((base) << 21) | ((src) << 16) | neg | ((r) ? 0x2 : 0))
58
59 /* only works on right half SP registers */
60 #define FCNV(src, ssng, dest, dsng) (0x38000200 | ((src) << 21) | ((ssng) ? 0x80 : 0x800) | (dest) | ((dsng) ? 0x40 : 0x2000))
61
62 #define LDIL(im21, dest) (0x20000000 | im21 | ((dest) << 21))
63
64 #define LDO(off, base, dest, neg) (0x34000000 | (((off) & 0x1fff)) << 1 | ((base) << 21) | ((dest) << 16) | neg)
65
66 #define EXTRDU(src, pos, len, dest) (0xd8000000 | ((src) << 21) | ((dest) << 16) | ((pos) > 32 ? 0x800 : 0) | (((pos) & 31) << 5) | ((len) > 32 ? 0x1000 : 0) | (32 - (len & 31))) 
67
68 #define BVE(reg, link) (0xE8001000 | ((link ? 7 : 6) << 13) | ((reg) << 21))
69
70 static unsigned int gen_copy(int src, int dest)
71 {
72         if (debug_asm)
73                 fprintf(stderr, "COPY %d,%d\n", src, dest);
74         return COPY(src, dest);
75 }
76
77 static unsigned int gen_ldb(int disp, int base, int dest)
78 {
79         int neg = disp < 0;
80         if (debug_asm)
81                 fprintf(stderr, "LDB %d(%d),%d\n", disp, base, dest);
82         return LDB(disp, base, dest, neg);
83 }
84
85 static unsigned int gen_stb(int src, int disp, int base)
86 {
87         int neg = disp < 0;
88         if (debug_asm)
89                 fprintf(stderr, "STB %d,%d(%d)\n", src, disp, base);
90         return STB(src, disp, base, neg);
91 }
92
93 static unsigned int gen_ldh(int disp, int base, int dest)
94 {
95         int neg = disp < 0;
96         if (debug_asm)
97                 fprintf(stderr, "LDH %d(%d),%d\n", disp, base, dest);
98         g_assert((disp & 1) == 0);
99         return LDH(disp, base, dest, neg);
100 }
101
102 static unsigned int gen_sth(int src, int disp, int base)
103 {
104         int neg = disp < 0;
105         if (debug_asm)
106                 fprintf(stderr, "STH %d,%d(%d)\n", src, disp, base);
107         g_assert((disp & 1) == 0);
108         return STH(src, disp, base, neg);
109 }
110
111 static unsigned int gen_ldw(int disp, int base, int dest)
112 {
113         int neg = disp < 0;
114         if (debug_asm)
115                 fprintf(stderr, "LDW %d(%d),%d\n", disp, base, dest);
116         g_assert((disp & 3) == 0);
117         return LDW(disp, base, dest, neg);
118 }
119
120 static unsigned int gen_stw(int src, int disp, int base)
121 {
122         int neg = disp < 0;
123         if (debug_asm)
124                 fprintf(stderr, "STW %d,%d(%d)\n", src, disp, base);
125         g_assert((disp & 3) == 0);
126         return STW(src, disp, base, neg);
127 }
128
129 static unsigned int gen_ldd(int disp, int base, int dest)
130 {
131         int neg = disp < 0;
132         if (debug_asm)
133                 fprintf(stderr, "LDD %d(%d),%d\n", disp, base, dest);
134         g_assert((disp & 7) == 0);
135         return LDD(disp >> 3, base, dest, 0, 0, neg);
136 }
137
138 static unsigned int gen_lddmb(int disp, int base, int dest)
139 {
140         int neg = disp < 0;
141         if (debug_asm)
142                 fprintf(stderr, "LDD,MB %d(%d),%d\n", disp, base, dest);
143         g_assert((disp & 7) == 0);
144         return LDD(disp >> 3, base, dest, 1, 1, neg);
145 }
146
147 static unsigned int gen_std(int src, int disp, int base)
148 {
149         int neg = disp < 0;
150         g_assert((disp & 7) == 0);
151         if (debug_asm)
152                 fprintf(stderr, "STD %d,%d(%d)\n", src, disp, base);
153         return STD(src, disp >> 3, base, 0, 0, neg);
154 }
155
156 static unsigned int gen_fldd(int disp, int base, int dest)
157 {
158         int neg = disp < 0;
159         if (debug_asm)
160                 fprintf(stderr, "FLDD %d(%d),%d\n", disp, base, dest);
161         g_assert((disp & 7) == 0);
162         return FLDD(disp >> 3, base, dest, 0, 0, neg);
163 }
164
165 static unsigned int gen_fstd(int src, int disp, int base)
166 {
167         int neg = disp < 0;
168         g_assert((disp & 7) == 0);
169         if (debug_asm)
170                 fprintf(stderr, "FSTD %d,%d(%d)\n", src, disp, base);
171         return FSTD(src, disp >> 3, base, 0, 0, neg);
172 }
173
174 static unsigned int gen_fldw(int disp, int base, int dest)
175 {
176         int neg = disp < 0;
177         if (debug_asm)
178                 fprintf(stderr, "FLDW %d(%d),%dr\n", disp, base, dest);
179         g_assert((disp & 3) == 0);
180         return FLDW(disp >> 2, base, dest, 1, neg);
181 }
182
183 static unsigned int gen_fstw(int src, int disp, int base)
184 {
185         int neg = disp < 0;
186         g_assert((disp & 3) == 0);
187         if (debug_asm)
188                 fprintf(stderr, "FSTW %dr,%d(%d)\n", src, disp, base);
189         return FSTW(src, disp >> 2, base, 1, neg);
190 }
191
192 static unsigned int gen_fcnv_dbl_sng(int src, int dest)
193 {
194         if (debug_asm)
195                 fprintf(stderr, "FCNV,DBL,SGL %d,%dr\n", src, dest);
196         return FCNV(src, 0, dest, 1);
197 }
198
199 static unsigned int gen_fcnv_sng_dbl(int src, int dest)
200 {
201         if (debug_asm)
202                 fprintf(stderr, "FCNV,SGL,DBL %dr,%d\n", src, dest);
203         return FCNV(src, 1, dest, 0);
204 }
205
206 static unsigned int gen_stdma(int src, int disp, int base)
207 {
208         int neg = disp < 0;
209         g_assert((disp & 7) == 0);
210         if (debug_asm)
211                 fprintf(stderr, "STD,MA %d,%d(%d)\n", src, disp, base);
212         return STD(src, disp >> 3, base, 1, 0, neg);
213 }
214
215 /* load top 21 bits of val into reg */
216 static unsigned int gen_ldil(unsigned int val, int reg)
217 {
218         unsigned int t = (val >> 11) & 0x1fffff;
219         unsigned int im21 = ((t & 0x7c) << 14) | ((t & 0x180) << 7) | ((t & 0x3) << 12) | ((t & 0xffe00) >> 8) | ((t & 0x100000) >> 20);
220         return LDIL(reg, im21);
221 }
222
223 static unsigned int gen_ldo(int off, int base, int reg)
224 {
225         int neg = off < 0;
226         if (debug_asm)
227                 fprintf(stderr, "LDO %d(%d),%d\n", off, base, reg);
228         return LDO(off, base, reg, neg);
229 }
230
231 static unsigned int gen_nop(void)
232 {
233         if (debug_asm)
234                 fprintf(stderr, "NOP\n");
235         return NOP;
236 }
237
238 static unsigned int gen_bve(int reg, int link)
239 {
240         if (debug_asm)
241                 fprintf(stderr, "BVE%s (%d)%s\n", link ? ",L" : "", reg, link ? ",2" : "");
242         return BVE(reg, link);
243 }
244
245 static unsigned int gen_extrdu(int src, int pos, int len, int dest)
246 {
247         if (debug_asm)
248                 fprintf(stderr, "EXTRD,U %d,%d,%d,%d\n", src, pos, len, dest);
249         return EXTRDU(src, pos, len, dest);
250 }
251
252 static void flush_cache(void *address, int length)
253 {
254 #ifdef __GNUC__
255 #error "currently only supports the HP C compiler"
256 #else
257         int cache_line_size = 16;
258         ulong_t end = (ulong_t)address + length;
259         register ulong_t sid;
260         register ulong_t offset = (ulong_t) address;
261         register ulong_t r0 = 0;
262
263         _asm("LDSID", 0, offset, sid);
264         _asm("MTSP", sid, 0);
265         _asm("FDC", r0, 0, offset);
266         offset = (offset + (cache_line_size - 1)) & ~(cache_line_size - 1);
267         while (offset < end) {
268                 (void)_asm("FDC", r0, 0, offset);
269                 offset += cache_line_size;
270         }
271         _asm("SYNC");
272         offset = (ulong_t) address;
273         _asm("FIC", r0, 0, offset);
274         offset = (offset + (cache_line_size - 1)) & ~(cache_line_size - 1);
275         while (offset < end) {
276                 (void)_asm("FIC", r0, 0, offset);
277                 offset += cache_line_size;
278         }
279         _asm("SYNC");
280         // sync needs at least 7 instructions after it... this is what is used for NOP
281         _asm("OR", 0, 0, 0);
282         _asm("OR", 0, 0, 0);
283         _asm("OR", 0, 0, 0);
284         _asm("OR", 0, 0, 0);
285         _asm("OR", 0, 0, 0);
286         _asm("OR", 0, 0, 0);
287         _asm("OR", 0, 0, 0);
288 #endif
289 }
290
291 #define ADD_INST(code, pc, gen_exp) ((code) == NULL ? (pc)++ : (code[(pc)++] = (gen_exp)))
292
293 /*
294  * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
295  */
296
297 MonoPIFunc
298 mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
299 {
300         int pc, save_pc;
301         int param;
302         void **descriptor;
303         unsigned int *code = NULL;
304         int arg_reg;
305 #define FP_ARG_REG(r) (4 + (26 - arg_reg))
306         int arg_offset;
307         int frame_size = 0;
308         int spill_offset;
309         int parameter_offset;
310         int parameter_slot;
311         int args_on_stack;
312
313         if (debug_asm) {
314                 fprintf(stderr, "trampoline: # params %d has this %d exp this %d string %d, ret type %d\n", 
315                         sig->param_count, sig->hasthis, sig->explicit_this, string_ctor, sig->ret->type);
316         }
317
318         // everything takes 8 bytes unless it is a bigger struct
319         for (param = 0; param < sig->param_count; param++) {
320                 if (sig->params[param]->byref)
321                         frame_size += 8;
322                 else {
323                         if (sig->params[param]->type != MONO_TYPE_VALUETYPE)
324                                 frame_size += 8;
325                         else {
326                                 if (sig->params [param]->data.klass->enumtype) 
327                                         frame_size += 8;
328                                 else {
329                                         frame_size += 15; // large structs are 16 byte aligned
330                                         frame_size &= ~15;
331                                         frame_size += mono_class_native_size (sig->params [param]->data.klass, NULL);
332                                         frame_size += 7;
333                                         frame_size &= ~7;
334                                 }
335                         }
336                 }
337         }
338                                 
339         if (sig->hasthis)
340                 frame_size += 8;
341         // 16 byte alignment
342         if ((frame_size & 15) != 0)
343                 frame_size += 8;
344         // minimum is 64 bytes
345         if (frame_size < 64)
346                 frame_size = 64;
347
348         if (debug_asm)
349                 fprintf(stderr, "outgoing frame size: %d\n", frame_size);
350
351         frame_size += 16; // for the frame marker (called routines stuff return address etc. here)
352         frame_size += 32; // spill area for r4, r5 and r27 (16 byte aligned)
353
354         spill_offset = -frame_size;
355         parameter_offset = spill_offset + 32; // spill area size is really 24
356         spill_offset += 8;
357
358         /* the rest executes twice - once to count instructions so we can
359            allocate memory in one block and once to fill it in... the count
360            should be pretty fast anyway...
361         */
362 generate:
363         pc = 0;
364         arg_reg = 26;
365         arg_offset = 0;
366         args_on_stack = 0;
367         parameter_slot = parameter_offset;
368
369         ADD_INST(code, pc, gen_std(2, -16, 30));  // STD          %r2,-16(%r30)   
370         ADD_INST(code, pc, gen_stdma(3, frame_size, 30));
371         ADD_INST(code, pc, gen_std(4, spill_offset, 30));
372         ADD_INST(code, pc, gen_std(5, spill_offset + 8, 30));
373         ADD_INST(code, pc, gen_copy(29, 3));       // COPY        %r29,%r3                
374         ADD_INST(code, pc, gen_std(27, spill_offset + 16, 30));
375         ADD_INST(code, pc, gen_nop());             // NOP                         
376
377         ADD_INST(code, pc, gen_std(26, -64, 29)); // STD          %r26,-64(%r29)  callme
378         ADD_INST(code, pc, gen_std(25, -56, 29)); // STD          %r25,-56(%r29)  retval
379         ADD_INST(code, pc, gen_std(24, -48, 29)); // STD          %r24,-48(%r29)  this_obj
380         ADD_INST(code, pc, gen_std(23, -40, 29)); // STD          %r23,-40(%r29)  arguments
381
382         if (sig->param_count > 0)
383                 ADD_INST(code, pc, gen_copy(23, 4));  // r4 is the current pointer to the stackval array of args
384
385         if (sig->hasthis) {
386                 if (sig->call_convention != MONO_CALL_THISCALL) {
387                         ADD_INST(code, pc, gen_copy(24, arg_reg));
388                         --arg_reg;
389                         parameter_slot += 8;
390                 } else  {
391                         fprintf(stderr, "case I didn't handle\n");
392                 }
393         }
394
395         for (param = 0; param < sig->param_count; param++) {
396                 int type = sig->params[param]->type;
397                 if (sig->params[param]->byref) {
398                         if (args_on_stack) {
399                                 ADD_INST(code, pc, gen_ldd(arg_offset, 4, 5));
400                                 ADD_INST(code, pc, gen_std(5, parameter_slot, 30));
401                         } else {
402                                 ADD_INST(code, pc, gen_ldd(arg_offset, 4, arg_reg));
403                                 --arg_reg;
404                         }
405                         arg_offset += sizeof(stackval);
406                         parameter_slot += 8;
407                         continue;
408                 }
409         typeswitch:
410                 switch (type) {
411                 case MONO_TYPE_CHAR:
412                 case MONO_TYPE_BOOLEAN:
413                 case MONO_TYPE_I1:
414                 case MONO_TYPE_U1:
415                 case MONO_TYPE_I2:
416                 case MONO_TYPE_U2:
417                 case MONO_TYPE_I4:
418                 case MONO_TYPE_U4:
419                         if (args_on_stack) {
420                                 ADD_INST(code, pc, gen_ldw(arg_offset, 4, 5));
421                                 switch (type) {
422                                 case MONO_TYPE_I4:
423                                 case MONO_TYPE_U4:
424                                         ADD_INST(code, pc, gen_stw(5, parameter_slot + 4, 30));
425                                         break;
426                                 case MONO_TYPE_CHAR:
427                                 case MONO_TYPE_I2:
428                                 case MONO_TYPE_U2:
429                                         ADD_INST(code, pc, gen_sth(5, parameter_slot + 6, 30));
430                                         break;
431                                 case MONO_TYPE_BOOLEAN:
432                                 case MONO_TYPE_I1:
433                                 case MONO_TYPE_U1:
434                                         ADD_INST(code, pc, gen_stb(5, parameter_slot + 7, 30));
435                                         break;
436                                 }
437                         } else {
438                                 ADD_INST(code, pc, gen_ldw(arg_offset, 4, arg_reg));
439                                 --arg_reg;
440                         }
441                         arg_offset += sizeof(stackval);
442                         parameter_slot += 8;
443                         break;
444                 case MONO_TYPE_I8:
445                 case MONO_TYPE_U8:
446                 case MONO_TYPE_I:
447                 case MONO_TYPE_U:
448                 case MONO_TYPE_STRING:
449                 case MONO_TYPE_OBJECT:
450                 case MONO_TYPE_CLASS:
451                 case MONO_TYPE_SZARRAY:
452                 case MONO_TYPE_PTR:
453                         if (args_on_stack) {
454                                 ADD_INST(code, pc, gen_ldd(arg_offset, 4, 5));
455                                 ADD_INST(code, pc, gen_std(5, parameter_slot, 30));
456                         } else {
457                                 ADD_INST(code, pc, gen_ldd(arg_offset, 4, arg_reg));
458                                 --arg_reg;
459                         }
460                         arg_offset += sizeof(stackval);
461                         parameter_slot += 8;
462                         break;
463                 case MONO_TYPE_R8:
464                         if (args_on_stack) {
465                                 ADD_INST(code, pc, gen_ldd(arg_offset, 4, 5));
466                                 ADD_INST(code, pc, gen_std(5, parameter_slot, 30));
467                         } else {
468                                 ADD_INST(code, pc, gen_fldd(arg_offset, 4, FP_ARG_REG(arg_reg)));
469                                 --arg_reg;
470                         }
471                         arg_offset += sizeof(stackval);
472                         parameter_slot += 8;
473                         break;
474                 case MONO_TYPE_R4:
475                         if (args_on_stack) {
476                                 ADD_INST(code, pc, gen_fldd(arg_offset, 4, 22));
477                                 ADD_INST(code, pc, gen_fcnv_dbl_sng(22, 22));
478                                 ADD_INST(code, pc, gen_fstw(22, parameter_slot + 4, 30));
479                         } else {
480                                 ADD_INST(code, pc, gen_fldd(arg_offset, 4, FP_ARG_REG(arg_reg)));
481                                 ADD_INST(code, pc, gen_fcnv_dbl_sng(FP_ARG_REG(arg_reg), FP_ARG_REG(arg_reg)));
482                                 --arg_reg;
483                         }
484                         arg_offset += sizeof(stackval);
485                         parameter_slot += 8;
486                         break;
487                 case MONO_TYPE_VALUETYPE:
488                         if (sig->params [param]->data.klass->enumtype) {
489                                 type = sig->params [param]->data.klass->enum_basetype->type;
490                                 goto typeswitch;
491                         } else {
492                                 int size = mono_class_native_size (sig->params [param]->data.klass, NULL);
493                                 // assumes struct is 8 byte aligned whatever its size... (as interp.c guarantees at present)
494                                 // copies multiple of 8 bytes which may include some trailing garbage but should be safe
495                                 if (size <= 8) {
496                                         if (args_on_stack) {
497                                                 ADD_INST(code, pc, gen_ldd(arg_offset, 4, 5));
498                                                 ADD_INST(code, pc, gen_ldd(0, 5, 5));
499                                                 ADD_INST(code, pc, gen_std(5, parameter_slot, 30));
500                                         } else {
501                                                 ADD_INST(code, pc, gen_ldd(arg_offset, 4, arg_reg));
502                                                 ADD_INST(code, pc, gen_ldd(0, arg_reg, arg_reg));
503                                                 --arg_reg;
504                                         }
505                                         parameter_slot += 8;
506                                 } else {
507                                         int soffset = 0;
508                                         if ((parameter_slot & 15) != 0) {
509                                                 --arg_reg;
510                                                 if (arg_reg < 19) {
511                                                         args_on_stack = 1;
512                                                 }
513                                                 parameter_slot += 8;
514                                         }
515                                         ADD_INST(code, pc, gen_ldd(arg_offset, 4, 5));
516                                         // might generate a lot of code for very large structs... should
517                                         // use a loop or routine call them
518                                         while (size > 0) {
519                                                 if (args_on_stack) {
520                                                         ADD_INST(code, pc, gen_ldd(soffset, 5, 31));
521                                                         ADD_INST(code, pc, gen_std(31, parameter_slot, 30));
522                                                 } else {
523                                                         ADD_INST(code, pc, gen_ldd(soffset, 5, arg_reg));
524                                                         --arg_reg;
525                                                         if (arg_reg < 19)
526                                                                 args_on_stack = 1;
527                                                 }
528                                                 parameter_slot += 8;
529                                                 soffset += 8;
530                                                 size -= 8;
531                                         }
532                                 }
533                                 arg_offset += sizeof(stackval);
534                                 break;
535                         }
536                         break;
537                 default:
538                         g_error ("mono_create_trampoline: unhandled arg type %d", type);
539                         return NULL;
540                 }
541
542                 if (arg_reg < 19) {
543                         args_on_stack = 1;
544                 }
545         }
546
547         // for large return structs just pass on the buffer given to us.
548         if (sig->ret->type == MONO_TYPE_VALUETYPE && sig->ret->data.klass->enumtype == 0) {
549                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
550                 if (size > 16) {
551                         ADD_INST(code, pc, gen_ldd(-56, 3, 28));
552                         ADD_INST(code, pc, gen_ldd(0, 28, 28));
553                 }
554         }
555
556         ADD_INST(code, pc, gen_nop());             // NOP                         
557         ADD_INST(code, pc, gen_ldd(-64, 29, 5));
558         ADD_INST(code, pc, gen_ldd(24, 5, 27));
559         ADD_INST(code, pc, gen_ldd(16, 5, 5));
560         ADD_INST(code, pc, gen_bve(5, 1));
561         ADD_INST(code, pc, gen_ldo(parameter_offset + 64, 30, 29));
562         ADD_INST(code, pc, gen_ldd(spill_offset + 16, 30, 27));
563         ADD_INST(code, pc, gen_nop());             // NOP                         
564         
565         if (string_ctor) {
566                 ADD_INST(code, pc, gen_ldd(-56, 3, 19)); // LDD  -56(%r3),%r19   
567                 ADD_INST(code, pc, gen_std(28, 0, 19));  // STD  %r28,0(%r19)    
568         }
569         else if (sig->ret->type != MONO_TYPE_VOID) {
570                 int type = sig->ret->type;
571
572         rettypeswitch:
573                 switch (type) {
574                 case MONO_TYPE_BOOLEAN:
575                 case MONO_TYPE_I1:
576                 case MONO_TYPE_U1:
577                         ADD_INST(code, pc, gen_ldd(-56, 3, 19)); // LDD  -56(%r3),%r19   
578                         ADD_INST(code, pc, gen_stb(28, 0, 19));  // STB  %r28,0(%r19)    
579                         break;
580                 case MONO_TYPE_I4:
581                 case MONO_TYPE_U4:
582                         ADD_INST(code, pc, gen_ldd(-56, 3, 19)); // LDD  -56(%r3),%r19   
583                         ADD_INST(code, pc, gen_stw(28, 0, 19));  // STW  %r28,0(%r19)    
584                         break;
585                 case MONO_TYPE_CHAR:
586                 case MONO_TYPE_I2:
587                 case MONO_TYPE_U2:
588                         ADD_INST(code, pc, gen_ldd(-56, 3, 19)); // LDD  -56(%r3),%r19   
589                         ADD_INST(code, pc, gen_sth(28, 0, 19));  // STH  %r28,0(%r19)
590                         break;
591                 case MONO_TYPE_I8:
592                 case MONO_TYPE_U8:
593                 case MONO_TYPE_I:
594                 case MONO_TYPE_U:
595                 case MONO_TYPE_STRING:
596                 case MONO_TYPE_OBJECT:
597                 case MONO_TYPE_CLASS:
598                 case MONO_TYPE_SZARRAY:
599                 case MONO_TYPE_PTR:
600                         ADD_INST(code, pc, gen_ldd(-56, 3, 19)); // LDD  -56(%r3),%r19   
601                         ADD_INST(code, pc, gen_std(28, 0, 19));  // STD  %r28,0(%r19)    
602                         break;
603                 case MONO_TYPE_R8:
604                         ADD_INST(code, pc, gen_ldd(-56, 3, 19)); // LDD  -56(%r3),%r19   
605                         ADD_INST(code, pc, gen_fstd(4, 0, 19));  // FSTD          %fr4,0(%r19)    
606                         break;
607                 case MONO_TYPE_R4:
608                         ADD_INST(code, pc, gen_ldd(-56, 3, 19)); // LDD  -56(%r3),%r19   
609                         ADD_INST(code, pc, gen_fstw(4, 0, 19));  // FSTW          %fr4r,0(%r19)    
610                         break;
611                 case MONO_TYPE_VALUETYPE:
612                         if (sig->ret->data.klass->enumtype) {
613                                 type = sig->ret->data.klass->enum_basetype->type;
614                                 goto rettypeswitch;
615                         } else {
616                                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
617                                 if (size <= 16) {
618                                         int reg = 28;
619                                         int off = 0;
620                                         ADD_INST(code, pc, gen_ldd(-56, 3, 19));
621                                         ADD_INST(code, pc, gen_ldd(0, 19, 19));
622                                         if (size > 8) {
623                                                 ADD_INST(code, pc, gen_std(28, 0, 19)); 
624                                                 size -= 8;
625                                                 reg = 29;
626                                                 off += 8;
627                                         }
628                                         // get rest of value right aligned in the register
629                                         ADD_INST(code, pc, gen_extrdu(reg, 8 * size - 1, 8 * size, reg));
630                                         if ((size & 1) != 0) {
631                                                 ADD_INST(code, pc, gen_stb(reg, off + size - 1, 19));
632                                                 ADD_INST(code, pc, gen_extrdu(reg, 55, 56, reg));
633                                                 size -= 1;
634                                         }
635                                         if ((size & 2) != 0) {
636                                                 ADD_INST(code, pc, gen_sth(reg, off + size - 2, 19));
637                                                 ADD_INST(code, pc, gen_extrdu(reg, 47, 48, reg));
638                                                 size -= 2;
639                                         }
640                                         if ((size & 4) != 0)
641                                                 ADD_INST(code, pc, gen_stw(reg, off + size - 4, 19));
642                                 }
643                                 break;
644                         }
645                 default:
646                         g_error ("mono_create_trampoline: unhandled ret type %d", type);
647                         return NULL;
648                 }
649         }
650
651         ADD_INST(code, pc, gen_ldd(-frame_size-16, 30, 2));
652         ADD_INST(code, pc, gen_ldd(spill_offset, 30, 4));
653         ADD_INST(code, pc, gen_ldd(spill_offset + 8, 30, 5));
654         ADD_INST(code, pc, gen_bve(2, 0));
655         ADD_INST(code, pc, gen_lddmb(-frame_size, 30, 3));
656
657         if (code == NULL) {
658                 descriptor = (void **)g_malloc(4 * sizeof(void *) + pc * sizeof(unsigned int));
659                 code = (unsigned int *)((char *)descriptor + 4 * sizeof(void *));
660                 save_pc = pc;
661                 goto generate;
662         } else 
663                 g_assert(pc == save_pc);
664
665         if (debug_asm)
666                 fprintf(stderr, "generated: %d bytes\n", pc * 4);
667
668         // must do this so we can actually execute the code we just put in memory
669         flush_cache(code, 4 * pc);
670
671         descriptor[0] = 0;
672         descriptor[1] = 0;
673         descriptor[2] = code;
674         descriptor[3] = 0;
675
676         return (MonoPIFunc)descriptor;
677 }
678
679 void *
680 mono_arch_create_method_pointer (MonoMethod *method)
681 {
682         MonoMethodSignature *sig = method->signature;
683         MonoJitInfo *ji;
684         int i;
685         int pc;
686         int param;
687         void **descriptor = NULL;
688         void **data = NULL;
689         unsigned int *code = NULL;
690         int arg_reg = 26;
691         int arg_offset = 0;
692         int frame_size;
693         int invoke_rec_offset;
694         int stack_vals_offset;
695         int stack_val_pos;
696         int arg_val_pos;
697         int spill_offset;
698         int *vtoffsets;
699         int t;
700
701         if (debug_asm) {
702                 fprintf(stderr, "mono_create_method_pointer %s: flags %d\n", method->name, method->flags);
703                 fprintf(stderr, "method: # params %d has this %d exp this %d\n", sig->param_count, sig->hasthis, sig->explicit_this);
704                 fprintf(stderr, "ret %d\n", sig->ret->type);
705                 for (i = 0; i < sig->param_count; i++)
706                         fprintf(stderr, "%d: %d\n", i, sig->params[i]->type);
707         }
708
709         // the extra stackval is for the return val if necessary
710         // the 64 is for outgoing parameters and the 16 is the frame marker.
711         // the other 16 is space for struct return vals < 16 bytes
712         frame_size = sizeof(MonoInvocation) + (sig->param_count + 1) * sizeof(stackval) + 16 + 64 + 16;
713         frame_size += 15;
714         frame_size &= ~15;
715         invoke_rec_offset = -frame_size;
716         vtoffsets = (int *)alloca(sig->param_count * sizeof(int));
717
718         t = invoke_rec_offset;
719
720         for (i = 0; i < sig->param_count; ++i)
721                 if (sig->params[i]->type == MONO_TYPE_VALUETYPE &&
722                     !sig->params[i]->data.klass->enumtype && !sig->params[i]->byref) {
723                         int size = mono_class_native_size (sig->params[i]->data.klass, NULL);
724                         size += 7;
725                         size &= ~7;
726                         t -= size;
727                         frame_size += size;
728                         vtoffsets[i] = t;
729                 }
730
731         stack_vals_offset = invoke_rec_offset + sizeof(MonoInvocation);
732         stack_vals_offset += 7;
733         stack_vals_offset &= ~7;
734         frame_size += 32;
735         frame_size += 15;
736         frame_size &= ~15;
737         spill_offset = -frame_size + 8;
738
739 generate:
740         stack_val_pos = stack_vals_offset;
741         arg_val_pos = -64;
742         pc = 0;
743
744         ADD_INST(code, pc, gen_std(2, -16, 30));
745         ADD_INST(code, pc, gen_stdma(3, frame_size, 30));
746         ADD_INST(code, pc, gen_std(4, spill_offset, 30));
747         ADD_INST(code, pc, gen_copy(29, 3));
748         ADD_INST(code, pc, gen_std(27, spill_offset + 8, 30));
749         ADD_INST(code, pc, gen_std(28, spill_offset + 16, 30));
750         ADD_INST(code, pc, gen_nop());
751
752         ADD_INST(code, pc, gen_std(26, -64, 29)); // STD          %r26,-64(%r29)
753         ADD_INST(code, pc, gen_std(25, -56, 29)); // STD          %r25,-56(%r29)
754         ADD_INST(code, pc, gen_std(24, -48, 29)); // STD          %r24,-48(%r29)
755         ADD_INST(code, pc, gen_std(23, -40, 29)); // STD          %r23,-40(%r29)
756         ADD_INST(code, pc, gen_std(22, -32, 29)); // STD          %r22,-32(%r29)
757         ADD_INST(code, pc, gen_std(21, -24, 29)); // STD          %r21,-24(%r29)
758         ADD_INST(code, pc, gen_std(20, -16, 29)); // STD          %r20,-16(%r29)
759         ADD_INST(code, pc, gen_std(19, -8, 29));  // STD          %r19,-8(%r29)
760
761         ADD_INST(code, pc, gen_std(0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, parent), 30));
762         ADD_INST(code, pc, gen_std(0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, child), 30));
763         ADD_INST(code, pc, gen_std(0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, ex), 30));
764         ADD_INST(code, pc, gen_std(0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, ex_handler), 30));
765         ADD_INST(code, pc, gen_std(0, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, ip), 30));
766
767         if (data != NULL)
768                 data[0] = method;
769         ADD_INST(code, pc, gen_ldd(0, 27, 19));
770         ADD_INST(code, pc, gen_std(19, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, method), 30));
771
772         if (sig->hasthis) {
773                 if (sig->call_convention != MONO_CALL_THISCALL) {
774                         ADD_INST(code, pc, gen_std(arg_reg, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, obj), 30));
775                         arg_val_pos += 8;
776                 } else {
777                         fprintf(stderr, "case I didn't handle 2\n");
778                 }
779         }
780
781         if (data != NULL)
782                 data[2] = (void *)stackval_from_data;
783
784         for (i = 0; i < sig->param_count; ++i) {
785                 if (data != NULL)
786                         data[4 + i] = sig->params[i];
787                 ADD_INST(code, pc, gen_ldd((4 + i) * 8, 27, 26)); // LDD          x(%r27),%r26 == type
788                 ADD_INST(code, pc, gen_ldo(stack_val_pos, 30, 25)); // LDD      x(%r30),%r25 == &stackval
789                 if (sig->params[i]->byref) {
790                         ADD_INST(code, pc, gen_ldo(arg_val_pos, 3, 24));
791                 } else {
792                         int type = sig->params[i]->type;
793                 typeswitch:
794                         switch (type) {
795                         case MONO_TYPE_I8:
796                         case MONO_TYPE_U8:
797                         case MONO_TYPE_I:
798                         case MONO_TYPE_U:
799                         case MONO_TYPE_STRING:
800                         case MONO_TYPE_OBJECT:
801                         case MONO_TYPE_CLASS:
802                         case MONO_TYPE_SZARRAY:
803                         case MONO_TYPE_PTR:
804                         case MONO_TYPE_R8:
805                                 ADD_INST(code, pc, gen_ldo(arg_val_pos, 3, 24));
806                                 break;
807                         case MONO_TYPE_I4:
808                         case MONO_TYPE_U4:
809                                 ADD_INST(code, pc, gen_ldo(arg_val_pos + 4, 3, 24));
810                                 break;
811                         case MONO_TYPE_CHAR:
812                         case MONO_TYPE_I2:
813                         case MONO_TYPE_U2:
814                                 ADD_INST(code, pc, gen_ldo(arg_val_pos + 6, 3, 24));
815                                 break;
816                         case MONO_TYPE_I1:
817                         case MONO_TYPE_U1:
818                         case MONO_TYPE_BOOLEAN:
819                                 ADD_INST(code, pc, gen_ldo(arg_val_pos + 7, 3, 24));
820                                 break;
821                         case MONO_TYPE_VALUETYPE:
822                                 if (sig->params [i]->data.klass->enumtype) {
823                                         type = sig->params [i]->data.klass->enum_basetype->type;
824                                         goto typeswitch;
825                                 } else {
826                                         int size = mono_class_native_size (sig->params[i]->data.klass, NULL);
827                                         if (size <= 8)
828                                                 ADD_INST(code, pc, gen_ldo(arg_val_pos, 3, 24));
829                                         else {
830                                                 arg_val_pos += 15;
831                                                 arg_val_pos &= ~15;
832                                                 ADD_INST(code, pc, gen_ldo(arg_val_pos, 3, 24));
833                                         }
834
835                                         arg_val_pos += size;
836                                         arg_val_pos += 7;
837                                         arg_val_pos &= ~7;
838                                         arg_val_pos -=8 ; // as it is incremented later
839
840                                         ADD_INST(code, pc, gen_ldo(vtoffsets[i], 30, 19));
841                                         ADD_INST(code, pc, gen_std(19, 0, 25));
842                                 }
843                                 break;
844                         default:
845                                 fprintf(stderr, "can not cope in create method pointer %d\n", sig->params[i]->type);
846                                 break;
847                         }
848                 }
849
850                 ADD_INST(code, pc, gen_ldo(sig->pinvoke, 0, 23)); // LDI sig->pinvoke,%r23
851                 ADD_INST(code, pc, gen_ldd(16, 27, 19));        // LDD     x(%r27),%r19 == stackval_from_data
852                 ADD_INST(code, pc, gen_ldd(16, 19, 20));        // LDD     16(%r19),%r20   
853                 ADD_INST(code, pc, gen_ldd(24, 19, 27));        // LDD     24(%r19),%r27   
854                 ADD_INST(code, pc, gen_bve(20, 1));             // BVE,L   (%r20),%r2      
855                 ADD_INST(code, pc, gen_ldo(-16, 30, 29));       // LDO     -16(%r30),%r29
856                 ADD_INST(code, pc, gen_ldd(spill_offset + 8, 30, 27));
857
858                 stack_val_pos += sizeof (stackval);
859                 arg_val_pos += 8;
860                 g_assert(stack_val_pos < -96);
861         }
862         
863         ADD_INST(code, pc, gen_ldo(stack_vals_offset, 30, 19));
864         ADD_INST(code, pc, gen_std(19, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, stack_args), 30));
865         ADD_INST(code, pc, gen_ldo(stack_val_pos, 30, 19));
866         ADD_INST(code, pc, gen_std(19, invoke_rec_offset + G_STRUCT_OFFSET (MonoInvocation, retval), 30));
867
868         if (sig->ret->type == MONO_TYPE_VALUETYPE && !sig->ret->data.klass->enumtype) {
869                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
870                 // for large return structs pass on the pointer given us by our caller.
871                 if (size > 16)
872                         ADD_INST(code, pc, gen_ldd(spill_offset + 16, 30, 28));
873                 else // use space left on stack for the return value
874                         ADD_INST(code, pc, gen_ldo(stack_val_pos + sizeof(stackval), 30, 28));
875                 ADD_INST(code, pc, gen_std(28, stack_val_pos, 30));
876         }
877
878         ADD_INST(code, pc, gen_ldo(invoke_rec_offset, 30, 26)); // address of invocation
879
880         if (data != NULL)
881                 data[1] = (void *)ves_exec_method;
882         ADD_INST(code, pc, gen_ldd(8, 27, 19)); // LDD     8(%r27),%r19
883         ADD_INST(code, pc, gen_ldd(16, 19, 20));        // LDD     16(%r19),%r20   
884         ADD_INST(code, pc, gen_ldd(24, 19, 27));        // LDD     24(%r19),%r27   
885         ADD_INST(code, pc, gen_bve(20, 1));             // BVE,L   (%r20),%r2      
886         ADD_INST(code, pc, gen_ldo(-16, 30, 29));       // LDO     -16(%r30),%r29
887         ADD_INST(code, pc, gen_ldd(spill_offset + 8, 30, 27));
888         if (sig->ret->byref) {
889                 fprintf(stderr, "can'ty cope with ret byref\n");
890         } else {
891                 int simpletype = sig->ret->type;        
892         enum_retvalue:
893                 switch (simpletype) {
894                 case MONO_TYPE_VOID:
895                         break;
896                 case MONO_TYPE_BOOLEAN:
897                 case MONO_TYPE_I1:
898                 case MONO_TYPE_U1:
899                 case MONO_TYPE_CHAR:
900                 case MONO_TYPE_I2:
901                 case MONO_TYPE_U2:
902                 case MONO_TYPE_I4:
903                 case MONO_TYPE_U4:
904                         ADD_INST(code, pc, gen_ldw(stack_val_pos, 30, 28)); // LDW      x(%r30),%r28
905                         break;
906                 case MONO_TYPE_I8:
907                 case MONO_TYPE_U8:
908                 case MONO_TYPE_I:
909                 case MONO_TYPE_U:
910                 case MONO_TYPE_STRING:
911                 case MONO_TYPE_OBJECT:
912                 case MONO_TYPE_CLASS:
913                 case MONO_TYPE_SZARRAY:
914                 case MONO_TYPE_PTR:
915                         ADD_INST(code, pc, gen_ldd(stack_val_pos, 30, 28)); // LDD      x(%r30),%r28
916                         break;
917                 case MONO_TYPE_R8:
918                         ADD_INST(code, pc, gen_fldd(stack_val_pos, 30, 4)); // FLDD      x(%r30),%fr4
919                         break;
920                 case MONO_TYPE_VALUETYPE:
921                         if (sig->ret->data.klass->enumtype) {
922                                 simpletype = sig->ret->data.klass->enum_basetype->type;
923                                 goto enum_retvalue;
924                         } else {
925                                 int size = mono_class_native_size (sig->ret->data.klass, NULL);
926                                 if (size <= 16) {
927                                         ADD_INST(code, pc, gen_ldd(stack_val_pos, 30, 28));
928                                         if (size > 8)
929                                                 ADD_INST(code, pc, gen_ldd(8, 28, 29)); 
930                                         ADD_INST(code, pc, gen_ldd(0, 28, 28)); 
931                                 }
932                         }
933                         break;
934                 default:
935                         fprintf(stderr, "can't cope with ret type %d\n", simpletype);
936                         return NULL;
937                 }
938         }
939
940         ADD_INST(code, pc, gen_ldd(-frame_size-16, 30, 2));
941         ADD_INST(code, pc, gen_ldd(spill_offset, 30, 4));
942         ADD_INST(code, pc, gen_bve(2, 0));
943         ADD_INST(code, pc, gen_lddmb(-frame_size, 30, 3));
944         if (code == NULL) {
945                 descriptor = (void **)malloc((8 + sig->param_count) * sizeof(void *) + sizeof(unsigned int) * pc);
946                 data = descriptor + 4;
947                 code = (unsigned int *)(data + 4 + sig->param_count);
948                 goto generate;
949         }
950
951         flush_cache(code, 4 * pc);
952
953         descriptor[0] = 0;
954         descriptor[1] = 0;
955         descriptor[2] = code;
956         descriptor[3] = data;
957
958         ji = g_new0 (MonoJitInfo, 1);
959         ji->method = method;
960         ji->code_size = 4; // does this matter?
961         ji->code_start = descriptor;
962
963         mono_jit_info_table_add (mono_root_domain, ji);
964
965         return ji->code_start;
966 }