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