New compilation engine for Mono
[mono.git] / mono / mini / jit-icalls.c
1 /*
2  * jit-icalls.c: internal calls used by the JIT
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <math.h>
12
13 static void*
14 mono_ldftn (MonoMethod *method) 
15 {
16         gpointer addr;
17
18         MONO_ARCH_SAVE_REGS;
19
20         EnterCriticalSection (metadata_section);
21         addr = mono_compile_method (method);
22         LeaveCriticalSection (metadata_section);
23
24         return addr;
25 }
26
27 static void*
28 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
29 {
30         MONO_ARCH_SAVE_REGS;
31         
32         method = mono_object_get_virtual_method (obj, method);
33         return mono_ldftn (method);
34 }
35
36 static void
37 helper_initobj (void *addr, int size)
38 {
39         MONO_ARCH_SAVE_REGS;
40
41         memset (addr, 0, size);
42 }
43
44 static void
45 helper_memcpy (void *addr, void *src, int size)
46 {
47         MONO_ARCH_SAVE_REGS;
48
49         memcpy (addr, src, size);
50 }
51
52 static void
53 helper_memset (void *addr, int val, int size)
54 {
55         MONO_ARCH_SAVE_REGS;
56
57         memset (addr, val, size);
58 }
59
60 static gint64 
61 mono_llmult (gint64 a, gint64 b)
62 {
63         MONO_ARCH_SAVE_REGS;
64         return a * b;
65 }
66
67 static guint64  
68 mono_llmult_ovf_un (guint32 al, guint32 ah, guint32 bl, guint32 bh)
69 {
70         guint64 res, t1;
71
72         MONO_ARCH_SAVE_REGS;
73
74         // fixme: this is incredible slow
75
76         if (ah && bh)
77                 goto raise_exception;
78
79         res = (guint64)al * (guint64)bl;
80
81         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
82
83         if (t1 > 0xffffffff)
84                 goto raise_exception;
85
86         res += ((guint64)t1) << 32; 
87
88         return res;
89
90  raise_exception:
91         mono_raise_exception (mono_get_exception_overflow ());
92         return 0;
93 }
94
95
96 static guint64  
97 mono_llmult_ovf (guint32 al, gint32 ah, guint32 bl, gint32 bh) 
98 {
99         /*
100         Use Karatsuba algorithm where:
101                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
102                 where Ah is the "high half" (most significant 32 bits) of a and
103                 where Al is the "low half" (least significant 32 bits) of a and
104                 where  Bh is the "high half" of b and Bl is the "low half" and
105                 where R is the Radix or "size of the half" (in our case 32 bits)
106
107         Note, for the product of two 64 bit numbers to fit into a 64
108         result, ah and/or bh must be 0.  This will save us from doing
109         the AhBh term at all.
110
111         Also note that we refactor so that we don't overflow 64 bits with 
112         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
113         */
114
115         gint64 res, t1;
116         gint32 sign;
117
118         MONO_ARCH_SAVE_REGS;
119
120         /* need to work with absoulte values, so find out what the
121            resulting sign will be and convert any negative numbers
122            from two's complement
123         */
124         sign = ah ^ bh;
125         if (ah < 0) {
126                 /* flip the bits and add 1 */
127                 ah ^= ~0;
128                 if (al ==  0)
129                         ah += 1;
130                 else {
131                         al ^= ~0;
132                         al +=1;
133                 }
134         }
135
136         if (bh < 0) {
137                 /* flip the bits and add 1 */
138                 bh ^= ~0;
139                 if (bl ==  0)
140                         bh += 1;
141                 else {
142                         bl ^= ~0;
143                         bl +=1;
144                 }
145         }
146                 
147         /* we overflow for sure if both upper halves are greater 
148            than zero because we would need to shift their 
149            product 64 bits to the left and that will not fit
150            in a 64 bit result */
151         if (ah && bh)
152                 goto raise_exception;
153
154         /* do the AlBl term first */
155         t1 = (gint64)al * (gint64)bl;
156
157         res = t1;
158
159         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
160         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
161         t1 <<= 32;
162         /* check for overflow */
163         if (t1 > (0x7FFFFFFFFFFFFFFF - res))
164                 goto raise_exception;
165
166         res += t1;
167
168         if (sign < 0)
169                 return -res;
170         else
171                 return res;
172
173  raise_exception:
174         mono_raise_exception (mono_get_exception_overflow ());
175         return 0;
176 }
177
178 static gint64 
179 mono_lldiv (gint64 a, gint64 b)
180 {
181         MONO_ARCH_SAVE_REGS;
182
183         return a / b;
184 }
185
186 static gint64 
187 mono_llrem (gint64 a, gint64 b)
188 {
189         MONO_ARCH_SAVE_REGS;
190
191         return a % b;
192 }
193
194 static guint64 
195 mono_lldiv_un (guint64 a, guint64 b)
196 {
197         MONO_ARCH_SAVE_REGS;
198
199         return a / b;
200 }
201
202 static guint64 
203 mono_llrem_un (guint64 a, guint64 b)
204 {
205         MONO_ARCH_SAVE_REGS;
206
207         return a % b;
208 }
209
210 static guint64 
211 mono_lshl (guint64 a, gint32 shamt)
212 {
213         guint64 res;
214
215         MONO_ARCH_SAVE_REGS;
216         res = a << shamt;
217
218         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
219
220         return res;
221 }
222
223 static guint64 
224 mono_lshr_un (guint64 a, gint32 shamt)
225 {
226         guint64 res;
227
228         MONO_ARCH_SAVE_REGS;
229         res = a >> shamt;
230
231         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
232
233         return res;
234 }
235
236 static gint64 
237 mono_lshr (gint64 a, gint32 shamt)
238 {
239         gint64 res;
240
241         MONO_ARCH_SAVE_REGS;
242         res = a >> shamt;
243
244         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
245
246         return res;
247 }
248
249 /**
250  * ves_array_element_address:
251  * @this: a pointer to the array object
252  *
253  * Returns: the address of an array element.
254  */
255 static gpointer 
256 ves_array_element_address (MonoArray *this, ...)
257 {
258         MonoClass *class;
259         va_list ap;
260         int i, ind, esize;
261         gpointer ea;
262
263         MONO_ARCH_SAVE_REGS;
264
265         g_assert (this != NULL);
266
267         va_start(ap, this);
268
269         class = this->obj.vtable->klass;
270
271         ind = va_arg(ap, int);
272         g_assert (this->bounds != NULL);
273
274         ind -= this->bounds [0].lower_bound;
275         for (i = 1; i < class->rank; i++) {
276                 ind = ind*this->bounds [i].length + va_arg(ap, int) -
277                         this->bounds [i].lower_bound;;
278         }
279
280         if (ind >= this->max_length)
281                 mono_raise_exception (mono_get_exception_index_out_of_range ());
282
283         esize = mono_array_element_size (class);
284         ea = (gpointer*)((char*)this->vector + (ind * esize));
285
286         va_end(ap);
287
288         return ea;
289 }
290
291 static MonoArray *
292 mono_array_new_va (MonoMethod *cm, ...)
293 {
294         MonoDomain *domain = mono_domain_get ();
295         va_list ap;
296         guint32 *lengths;
297         guint32 *lower_bounds;
298         int pcount;
299         int rank;
300         int i, d;
301
302         MONO_ARCH_SAVE_REGS;
303
304         pcount = cm->signature->param_count;
305         rank = cm->klass->rank;
306
307         va_start (ap, cm);
308         
309         lengths = alloca (sizeof (guint32) * pcount);
310         for (i = 0; i < pcount; ++i)
311                 lengths [i] = d = va_arg(ap, int);
312
313         if (rank == pcount) {
314                 /* Only lengths provided. */
315                 lower_bounds = NULL;
316         } else {
317                 g_assert (pcount == (rank * 2));
318                 /* lower bounds are first. */
319                 lower_bounds = lengths;
320                 lengths += rank;
321         }
322         va_end(ap);
323
324         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
325 }
326
327 static gpointer
328 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
329 {
330         MonoVTable *vtable;
331         
332         MONO_ARCH_SAVE_REGS;
333
334         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
335
336         mono_class_init (field->parent);
337
338         vtable = mono_class_vtable (domain, field->parent);
339
340         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
341
342         
343         return (char*)vtable->data + field->offset;
344 }
345
346 static gpointer
347 mono_ldtoken_wrapper (MonoImage *image, int token)
348 {
349         MonoClass *handle_class;
350         gpointer res;
351
352         MONO_ARCH_SAVE_REGS;
353         res = mono_ldtoken (image, token, &handle_class);       
354         mono_class_init (handle_class);
355
356         return res;
357 }
358
359 static guint64
360 mono_fconv_u8 (double v)
361 {
362         MONO_ARCH_SAVE_REGS;
363         return (guint64)v;
364 }
365
366 static guint32
367 mono_fconv_u4 (double v)
368 {
369         MONO_ARCH_SAVE_REGS;
370         return (guint32)v;
371 }
372
373 static gint64
374 mono_fconv_ovf_i8 (double v)
375 {
376         gint64 res;
377
378         MONO_ARCH_SAVE_REGS;
379
380         res = (gint64)v;
381
382         if (isnan(v) || v != res) {
383                 mono_raise_exception (mono_get_exception_overflow ());
384         }
385         return res;
386 }
387
388 static guint64
389 mono_fconv_ovf_u8 (double v)
390 {
391         guint64 res;
392
393         MONO_ARCH_SAVE_REGS;
394     
395         res = (guint64)v;
396
397         if (isnan(v) || v != res) {
398                 mono_raise_exception (mono_get_exception_overflow ());
399         }
400         return res;
401 }