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