Fixes PR52.
[cacao.git] / src / vm / array.c
1 /* src/vm/array.c - Java array functions
2
3    Copyright (C) 2007
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <stdint.h>
29
30 #include "native/llni.h"
31
32 #include "vm/array.h"
33 #include "vm/exceptions.h"
34 #include "vm/global.h"
35 #include "vm/primitive.h"
36 #include "vm/vm.h"
37
38
39 /* array_element_get ***********************************************************
40
41    Returns a boxed element of the given Java array.
42
43 *******************************************************************************/
44
45 java_handle_t *array_element_get(java_handle_t *a, int32_t index)
46 {
47         vftbl_t       *v;
48         int            type;
49         imm_union      value;
50         java_handle_t *o;
51
52         if (a == NULL) {
53                 exceptions_throw_nullpointerexception();
54                 return NULL;
55         }
56
57         v = LLNI_vftbl_direct(a);
58
59         type = v->arraydesc->arraytype;
60
61         value = array_element_primitive_get(a, index);
62
63         o = primitive_box(type, value);
64
65         return o;
66 }
67
68
69 /* array_element_set ***********************************************************
70
71    Sets a boxed element in the given Java array.
72
73 *******************************************************************************/
74
75 void array_element_set(java_handle_t *a, int32_t index, java_handle_t *o)
76 {
77         imm_union value;
78
79         value = primitive_unbox(o);
80
81         array_element_primitive_set(a, index, value);
82 }
83
84
85 /* array_element_primitive_get *************************************************
86
87    Returns a primitive element of the given Java array.
88
89 *******************************************************************************/
90
91 imm_union array_element_primitive_get(java_handle_t *a, int32_t index)
92 {
93         vftbl_t  *v;
94         int       type;
95         imm_union value;
96
97         if (a == NULL) {
98                 exceptions_throw_nullpointerexception();
99                 value.a = NULL;
100                 return value;
101         }
102
103         v = LLNI_vftbl_direct(a);
104
105         type = v->arraydesc->arraytype;
106
107         switch (type) {
108         case ARRAYTYPE_BOOLEAN:
109                 value.i = array_booleanarray_element_get((java_handle_booleanarray_t *) a, index);
110                 break;
111         case ARRAYTYPE_BYTE:
112                 value.i = array_bytearray_element_get((java_handle_bytearray_t *) a,
113                                                                                           index);
114                 break;
115         case ARRAYTYPE_CHAR:
116                 value.i = array_chararray_element_get((java_handle_chararray_t *) a,
117                                                                                           index);
118                 break;
119         case ARRAYTYPE_SHORT:
120                 value.i = array_shortarray_element_get((java_handle_shortarray_t *) a,
121                                                                                            index);
122                 break;
123         case ARRAYTYPE_INT:
124                 value.i = array_intarray_element_get((java_handle_intarray_t *) a,
125                                                                                          index);
126                 break;
127         case ARRAYTYPE_LONG:
128                 value.l = array_longarray_element_get((java_handle_longarray_t *) a,
129                                                                                           index);
130                 break;
131         case ARRAYTYPE_FLOAT:
132                 value.f = array_floatarray_element_get((java_handle_floatarray_t *) a,
133                                                                                            index);
134                 break;
135         case ARRAYTYPE_DOUBLE:
136                 value.d = array_doublearray_element_get((java_handle_doublearray_t *) a,
137                                                                                                 index);
138                 break;
139         case ARRAYTYPE_OBJECT:
140                 value.a = array_objectarray_element_get((java_handle_objectarray_t *) a,
141                                                                                                 index);
142                 break;
143         default:
144                 vm_abort("array_element_primitive_get: invalid array element type %d",
145                                  type);
146         }
147
148         return value;
149 }
150
151
152 /* array_element_primitive_set *************************************************
153
154    Sets a primitive element in the given Java array.
155
156 *******************************************************************************/
157
158 void array_element_primitive_set(java_handle_t *a, int32_t index, imm_union value)
159 {
160         vftbl_t *v;
161         int      type;
162
163         if (a == NULL) {
164                 exceptions_throw_nullpointerexception();
165                 return;
166         }
167
168         v = LLNI_vftbl_direct(a);
169
170         type = v->arraydesc->arraytype;
171
172         switch (type) {
173         case ARRAYTYPE_BOOLEAN:
174                 array_booleanarray_element_set((java_handle_booleanarray_t *) a,
175                                                                            index, value.i);
176                 break;
177         case ARRAYTYPE_BYTE:
178                 array_bytearray_element_set((java_handle_bytearray_t *) a,
179                                                                         index, value.i);
180                 break;
181         case ARRAYTYPE_CHAR:
182                 array_chararray_element_set((java_handle_chararray_t *) a,
183                                                                         index, value.i);
184                 break;
185         case ARRAYTYPE_SHORT:
186                 array_shortarray_element_set((java_handle_shortarray_t *) a,
187                                                                          index, value.i);
188                 break;
189         case ARRAYTYPE_INT:
190                 array_intarray_element_set((java_handle_intarray_t *) a,
191                                                                    index, value.i);
192                 break;
193         case ARRAYTYPE_LONG:
194                 array_longarray_element_set((java_handle_longarray_t *) a,
195                                                                         index, value.l);
196                 break;
197         case ARRAYTYPE_FLOAT:
198                 array_floatarray_element_set((java_handle_floatarray_t *) a,
199                                                                          index, value.f);
200                 break;
201         case ARRAYTYPE_DOUBLE:
202                 array_doublearray_element_set((java_handle_doublearray_t *) a,
203                                                                           index, value.d);
204                 break;
205         case ARRAYTYPE_OBJECT:
206                 array_objectarray_element_set((java_handle_objectarray_t *) a,
207                                                                           index, value.a);
208                 break;
209         default:
210                 vm_abort("array_element_primitive_set: invalid array element type %d",
211                                  type);
212         }
213 }
214
215
216 /* array_xxxarray_element_get **************************************************
217
218    Returns a primitive element of the given Java array.
219
220 *******************************************************************************/
221
222 #define ARRAY_TYPEARRAY_ELEMENT_GET(name, type)                                \
223 type array_##name##array_element_get(java_handle_##name##array_t *a, int32_t index) \
224 {                                                                              \
225         type    value;                                                             \
226         int32_t size;                                                              \
227                                                                                \
228         if (a == NULL) {                                                           \
229                 exceptions_throw_nullpointerexception();                               \
230                 return (type) 0;                                                       \
231         }                                                                          \
232                                                                                \
233         size = LLNI_array_size(a);                                                 \
234                                                                                \
235         if ((index < 0) || (index >= size)) {                                      \
236                 exceptions_throw_arrayindexoutofboundsexception();                     \
237                 return (type) 0;                                                       \
238         }                                                                          \
239                                                                                \
240         value = LLNI_array_direct(a, index);                                       \
241                                                                                \
242         return value;                                                              \
243 }
244
245 java_handle_t *array_objectarray_element_get(java_handle_objectarray_t *a, int32_t index)
246 {
247         java_handle_t *value;
248         int32_t size;
249
250         if (a == NULL) {
251                 exceptions_throw_nullpointerexception();
252                 return NULL;
253         }
254
255         size = LLNI_array_size(a);
256
257         if ((index < 0) || (index >= size)) {
258                 exceptions_throw_arrayindexoutofboundsexception();
259                 return NULL;
260         }
261
262         LLNI_CRITICAL_START;
263         value = LLNI_WRAP(LLNI_array_direct(a, index));
264         LLNI_CRITICAL_END;
265
266         return value;
267 }
268
269 ARRAY_TYPEARRAY_ELEMENT_GET(boolean, uint8_t)
270 ARRAY_TYPEARRAY_ELEMENT_GET(byte,    int8_t)
271 ARRAY_TYPEARRAY_ELEMENT_GET(char,    uint16_t)
272 ARRAY_TYPEARRAY_ELEMENT_GET(short,   int16_t)
273 ARRAY_TYPEARRAY_ELEMENT_GET(int,     int32_t)
274 ARRAY_TYPEARRAY_ELEMENT_GET(long,    int64_t)
275 ARRAY_TYPEARRAY_ELEMENT_GET(float,   float)
276 ARRAY_TYPEARRAY_ELEMENT_GET(double,  double)
277
278
279 /* array_xxxarray_element_set **************************************************
280
281    Sets a primitive element in the given Java array.
282
283 *******************************************************************************/
284
285 #define ARRAY_TYPEARRAY_ELEMENT_SET(name, type)                                \
286 void array_##name##array_element_set(java_handle_##name##array_t *a, int32_t index, type value) \
287 {                                                                              \
288         int32_t size;                                                              \
289                                                                                \
290         if (a == NULL) {                                                           \
291                 exceptions_throw_nullpointerexception();                               \
292                 return;                                                                \
293         }                                                                          \
294                                                                                \
295         size = LLNI_array_size(a);                                                 \
296                                                                                \
297         if ((index < 0) || (index >= size)) {                                      \
298                 exceptions_throw_arrayindexoutofboundsexception();                     \
299                 return;                                                                \
300         }                                                                          \
301                                                                                \
302         LLNI_array_direct(a, index) = value;                                       \
303 }
304
305 void array_objectarray_element_set(java_handle_objectarray_t *a, int32_t index, java_handle_t *value)
306 {
307         int32_t size;
308
309         if (a == NULL) {
310                 exceptions_throw_nullpointerexception();
311                 return;
312         }
313
314         /* Sanity check. */
315
316         assert(a->header.objheader.vftbl->arraydesc->arraytype == ARRAYTYPE_OBJECT);
317
318         if (value != NULL) {
319                 if (builtin_canstore(a, value) == false) {
320                         exceptions_throw_illegalargumentexception();
321                         return;
322                 }
323         }
324
325         size = LLNI_array_size(a);
326
327         if ((index < 0) || (index >= size)) {
328                 exceptions_throw_arrayindexoutofboundsexception();
329                 return;
330         }
331
332         LLNI_CRITICAL_START;
333         LLNI_array_direct(a, index) = LLNI_UNWRAP(value);
334         LLNI_CRITICAL_END;
335 }
336
337 ARRAY_TYPEARRAY_ELEMENT_SET(boolean, uint8_t)
338 ARRAY_TYPEARRAY_ELEMENT_SET(byte,    int8_t)
339 ARRAY_TYPEARRAY_ELEMENT_SET(char,    uint16_t)
340 ARRAY_TYPEARRAY_ELEMENT_SET(short,   int16_t)
341 ARRAY_TYPEARRAY_ELEMENT_SET(int,     int32_t)
342 ARRAY_TYPEARRAY_ELEMENT_SET(long,    int64_t)
343 ARRAY_TYPEARRAY_ELEMENT_SET(float,   float)
344 ARRAY_TYPEARRAY_ELEMENT_SET(double,  double)
345
346
347 /* array_length_get ***********************************************************
348
349    Returns a the length of the given Java array.
350
351    ARGUMENTS:
352        a ... Java array
353
354    RETURN VALUE:
355          -1 ... exception thrown
356            >= 0 ... length of the Java array
357
358 *******************************************************************************/
359
360 int32_t array_length_get(java_handle_t *a)
361 {
362         classinfo *c;
363         int32_t    size;
364
365         if (a == NULL) {
366                 exceptions_throw_nullpointerexception();
367                 return -1;
368         }
369
370         LLNI_class_get(a, c);
371
372         if (!class_is_array(c)) {
373 /*              exceptions_throw_illegalargumentexception("Argument is not an array"); */
374                 exceptions_throw_illegalargumentexception();
375                 return -1;
376         }
377
378         size = LLNI_array_size(a);
379
380         return size;
381 }
382
383
384 /*
385  * These are local overrides for various environment variables in Emacs.
386  * Please do not remove this and leave it at the end of the file, where
387  * Emacs will automagically detect them.
388  * ---------------------------------------------------------------------
389  * Local variables:
390  * mode: c
391  * indent-tabs-mode: t
392  * c-basic-offset: 4
393  * tab-width: 4
394  * End:
395  * vim:noexpandtab:sw=4:ts=4:
396  */