2004-01-15 Zoltan Varga <vargaz@freemail.hu>
[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         addr = mono_compile_method (method);
21
22         return addr;
23 }
24
25 static void*
26 mono_ldvirtfn (MonoObject *obj, MonoMethod *method) 
27 {
28         MONO_ARCH_SAVE_REGS;
29
30         method = mono_object_get_virtual_method (obj, method);
31         if (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
32                 method = mono_marshal_get_synchronized_wrapper (method);
33
34         return mono_ldftn (method);
35 }
36
37 static void
38 helper_initobj (void *addr, int size)
39 {
40         MONO_ARCH_SAVE_REGS;
41
42         memset (addr, 0, size);
43 }
44
45 static void
46 helper_memcpy (void *addr, void *src, int size)
47 {
48         MONO_ARCH_SAVE_REGS;
49
50         memcpy (addr, src, size);
51 }
52
53 static void
54 helper_memset (void *addr, int val, int size)
55 {
56         MONO_ARCH_SAVE_REGS;
57
58         memset (addr, val, size);
59 }
60
61 static void
62 helper_stelem_ref (MonoArray *array, int index, MonoObject *val)
63 {
64         MONO_ARCH_SAVE_REGS;
65
66         if (index >= array->max_length)
67                 mono_raise_exception (mono_get_exception_index_out_of_range ());
68
69         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
70                 mono_raise_exception (mono_get_exception_array_type_mismatch ());
71
72         mono_array_set (array, gpointer, index, val);
73 }
74
75 static void
76 helper_stelem_ref_check (MonoArray *array, MonoObject *val)
77 {
78         MONO_ARCH_SAVE_REGS;
79
80         if (val && !mono_object_isinst (val, array->obj.vtable->klass->element_class))
81                 mono_raise_exception (mono_get_exception_array_type_mismatch ());
82 }
83
84 static gint64 
85 mono_llmult (gint64 a, gint64 b)
86 {
87         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
88         return a * b;
89 }
90
91 static guint64  
92 mono_llmult_ovf_un (guint64 a, guint64 b)
93 {
94         guint32 al = a;
95         guint32 ah = a >> 32;
96         guint32 bl = b;
97         guint32 bh = b >> 32; 
98         guint64 res, t1;
99
100         MONO_ARCH_SAVE_REGS;
101
102         // fixme: this is incredible slow
103
104         if (ah && bh)
105                 goto raise_exception;
106
107         res = (guint64)al * (guint64)bl;
108
109         t1 = (guint64)ah * (guint64)bl + (guint64)al * (guint64)bh;
110
111         if (t1 > 0xffffffff)
112                 goto raise_exception;
113
114         res += ((guint64)t1) << 32; 
115
116         return res;
117
118  raise_exception:
119         mono_raise_exception (mono_get_exception_overflow ());
120         return 0;
121 }
122
123
124 static guint64  
125 mono_llmult_ovf (gint64 a, gint64 b) 
126 {
127         guint32 al = a;
128         gint32 ah = a >> 32;
129         guint32 bl = b;
130         gint32 bh = b >> 32; 
131         /*
132         Use Karatsuba algorithm where:
133                 a*b is: AhBh(R^2+R)+(Ah-Al)(Bl-Bh)R+AlBl(R+1)
134                 where Ah is the "high half" (most significant 32 bits) of a and
135                 where Al is the "low half" (least significant 32 bits) of a and
136                 where  Bh is the "high half" of b and Bl is the "low half" and
137                 where R is the Radix or "size of the half" (in our case 32 bits)
138
139         Note, for the product of two 64 bit numbers to fit into a 64
140         result, ah and/or bh must be 0.  This will save us from doing
141         the AhBh term at all.
142
143         Also note that we refactor so that we don't overflow 64 bits with 
144         intermediate results. So we use [(Ah-Al)(Bl-Bh)+AlBl]R+AlBl
145         */
146
147         gint64 res, t1;
148         gint32 sign;
149
150         MONO_ARCH_SAVE_REGS;
151
152         /* need to work with absoulte values, so find out what the
153            resulting sign will be and convert any negative numbers
154            from two's complement
155         */
156         sign = ah ^ bh;
157         if (ah < 0) {
158                 /* flip the bits and add 1 */
159                 ah ^= ~0;
160                 if (al ==  0)
161                         ah += 1;
162                 else {
163                         al ^= ~0;
164                         al +=1;
165                 }
166         }
167
168         if (bh < 0) {
169                 /* flip the bits and add 1 */
170                 bh ^= ~0;
171                 if (bl ==  0)
172                         bh += 1;
173                 else {
174                         bl ^= ~0;
175                         bl +=1;
176                 }
177         }
178                 
179         /* we overflow for sure if both upper halves are greater 
180            than zero because we would need to shift their 
181            product 64 bits to the left and that will not fit
182            in a 64 bit result */
183         if (ah && bh)
184                 goto raise_exception;
185
186         /* do the AlBl term first */
187         t1 = (gint64)al * (gint64)bl;
188
189         res = t1;
190
191         /* now do the [(Ah-Al)(Bl-Bh)+AlBl]R term */
192         t1 += (gint64)(ah - al) * (gint64)(bl - bh);
193         t1 <<= 32;
194         /* check for overflow */
195         if (t1 > (0x7FFFFFFFFFFFFFFFLL - res))
196                 goto raise_exception;
197
198         res += t1;
199
200         if (res < 0)
201                 goto raise_exception;
202
203         if (sign < 0)
204                 return -res;
205         else
206                 return res;
207
208  raise_exception:
209         mono_raise_exception (mono_get_exception_overflow ());
210         return 0;
211 }
212
213 static gint64 
214 mono_lldiv (gint64 a, gint64 b)
215 {
216         MONO_ARCH_SAVE_REGS;
217
218         return a / b;
219 }
220
221 static gint64 
222 mono_llrem (gint64 a, gint64 b)
223 {
224         MONO_ARCH_SAVE_REGS;
225
226         return a % b;
227 }
228
229 static guint64 
230 mono_lldiv_un (guint64 a, guint64 b)
231 {
232         MONO_ARCH_SAVE_REGS;
233
234         return a / b;
235 }
236
237 static guint64 
238 mono_llrem_un (guint64 a, guint64 b)
239 {
240         MONO_ARCH_SAVE_REGS;
241
242         return a % b;
243 }
244
245 static guint64 
246 mono_lshl (guint64 a, gint32 shamt)
247 {
248         guint64 res;
249
250         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
251         res = a << shamt;
252
253         /*printf ("TESTL %lld << %d = %lld\n", a, shamt, res);*/
254
255         return res;
256 }
257
258 static guint64 
259 mono_lshr_un (guint64 a, gint32 shamt)
260 {
261         guint64 res;
262
263         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
264         res = a >> shamt;
265
266         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
267
268         return res;
269 }
270
271 static gint64 
272 mono_lshr (gint64 a, gint32 shamt)
273 {
274         gint64 res;
275
276         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
277         res = a >> shamt;
278
279         /*printf ("TESTR %lld >> %d = %lld\n", a, shamt, res);*/
280
281         return res;
282 }
283
284 /**
285  * ves_array_element_address:
286  * @this: a pointer to the array object
287  *
288  * Returns: the address of an array element.
289  */
290 static gpointer 
291 ves_array_element_address (MonoArray *this, ...)
292 {
293         MonoClass *class;
294         va_list ap;
295         int i, ind, esize, realidx;
296         gpointer ea;
297
298         MONO_ARCH_SAVE_REGS;
299
300         g_assert (this != NULL);
301
302         va_start(ap, this);
303
304         class = this->obj.vtable->klass;
305
306         g_assert (this->bounds != NULL);
307
308         esize = mono_array_element_size (class);
309         ind = va_arg(ap, int);
310         ind -= (int)this->bounds [0].lower_bound;
311         if ((guint32)ind >= (guint32)this->bounds [0].length)
312                 mono_raise_exception (mono_get_exception_index_out_of_range ());
313         for (i = 1; i < class->rank; i++) {
314                 realidx = va_arg(ap, int) - (int)this->bounds [i].lower_bound;
315                 if ((guint32)realidx >= (guint32)this->bounds [i].length)
316                         mono_raise_exception (mono_get_exception_index_out_of_range ());
317                 ind *= this->bounds [i].length;
318                 ind += realidx;
319         }
320         esize *= ind;
321
322         ea = (gpointer*)((char*)this->vector + esize);
323
324         va_end(ap);
325
326         return ea;
327 }
328
329 static MonoArray *
330 mono_array_new_va (MonoMethod *cm, ...)
331 {
332         MonoDomain *domain = mono_domain_get ();
333         va_list ap;
334         guint32 *lengths;
335         guint32 *lower_bounds;
336         int pcount;
337         int rank;
338         int i, d;
339
340         MONO_ARCH_SAVE_REGS;
341
342         pcount = cm->signature->param_count;
343         rank = cm->klass->rank;
344
345         va_start (ap, cm);
346         
347         lengths = alloca (sizeof (guint32) * pcount);
348         for (i = 0; i < pcount; ++i)
349                 lengths [i] = d = va_arg(ap, int);
350
351         if (rank == pcount) {
352                 /* Only lengths provided. */
353                 lower_bounds = NULL;
354         } else {
355                 g_assert (pcount == (rank * 2));
356                 /* lower bounds are first. */
357                 lower_bounds = lengths;
358                 lengths += rank;
359         }
360         va_end(ap);
361
362         return mono_array_new_full (domain, cm->klass, lengths, lower_bounds);
363 }
364
365 static gpointer
366 mono_class_static_field_address (MonoDomain *domain, MonoClassField *field)
367 {
368         MonoVTable *vtable;
369         gpointer addr;
370         
371         MONO_ARCH_SAVE_REGS;
372
373         //printf ("SFLDA0 %s.%s::%s %d\n", field->parent->name_space, field->parent->name, field->name, field->offset, field->parent->inited);
374
375         mono_class_init (field->parent);
376
377         vtable = mono_class_vtable (domain, field->parent);
378         if (!vtable->initialized)
379                 mono_runtime_class_init (vtable);
380
381         //printf ("SFLDA1 %p\n", (char*)vtable->data + field->offset);
382
383         if (domain->special_static_fields && (addr = g_hash_table_lookup (domain->special_static_fields, field)))
384                 addr = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
385         else
386                 addr = (char*)vtable->data + field->offset;
387         
388         return addr;
389 }
390
391 static gpointer
392 mono_ldtoken_wrapper (MonoImage *image, int token)
393 {
394         MonoClass *handle_class;
395         gpointer res;
396
397         MONO_ARCH_SAVE_REGS;
398         res = mono_ldtoken (image, token, &handle_class);       
399         mono_class_init (handle_class);
400
401         return res;
402 }
403
404 static guint64
405 mono_fconv_u8 (double v)
406 {
407         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
408         return (guint64)v;
409 }
410
411 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
412 static gint64
413 mono_fconv_i8 (double v)
414 {
415         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
416         return (gint64)v;
417 }
418 #endif
419
420 static guint32
421 mono_fconv_u4 (double v)
422 {
423         /* no need, no exceptions: MONO_ARCH_SAVE_REGS;*/
424         return (guint32)v;
425 }
426
427 static gint64
428 mono_fconv_ovf_i8 (double v)
429 {
430         gint64 res;
431
432         MONO_ARCH_SAVE_REGS;
433
434         res = (gint64)v;
435
436         if (isnan(v) || v != res) {
437                 mono_raise_exception (mono_get_exception_overflow ());
438         }
439         return res;
440 }
441
442 static guint64
443 mono_fconv_ovf_u8 (double v)
444 {
445         guint64 res;
446
447         MONO_ARCH_SAVE_REGS;
448     
449         res = (guint64)v;
450
451         if (isnan(v) || v != res) {
452                 mono_raise_exception (mono_get_exception_overflow ());
453         }
454         return res;
455 }
456
457 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8
458 static double
459 mono_lconv_to_r8 (gint64 a)
460 {
461         return (double)a;
462 }
463 #endif
464
465 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R4
466 static float
467 mono_lconv_to_r4 (gint64 a)
468 {
469         return (float)a;
470 }
471 #endif
472
473 #ifdef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
474 static double
475 mono_lconv_to_r8_un (guint64 a)
476 {
477         return (double)a;
478 }
479 #endif
480