1097734dc7c6632096f9e6f3d70edd31477a4185
[cacao.git] / src / vm / array.hpp
1 /* src/vm/array.hpp - Java array functions
2
3    Copyright (C) 2007, 2009
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5    Copyright (C) 2008 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24 */
25
26
27 #ifndef _VM_ARRAY_HPP
28 #define _VM_ARRAY_HPP
29
30 #include "config.h"
31
32 #include <stdint.h>
33
34 #include "mm/gc.hpp" // XXX Remove me!
35
36 #include "native/llni.h" // XXX Remove me!
37
38 #include "vm/class.hpp"
39 #include "vm/exceptions.hpp"
40 #include "vm/global.h"
41 #include "vm/primitive.hpp"
42
43
44 /* array types ****************************************************************/
45
46 /* CAUTION: Don't change the numerical values! These constants (with
47    the exception of ARRAYTYPE_OBJECT) are used as indices in the
48    primitive type table. */
49
50 #define ARRAYTYPE_INT         PRIMITIVETYPE_INT
51 #define ARRAYTYPE_LONG        PRIMITIVETYPE_LONG
52 #define ARRAYTYPE_FLOAT       PRIMITIVETYPE_FLOAT
53 #define ARRAYTYPE_DOUBLE      PRIMITIVETYPE_DOUBLE
54 #define ARRAYTYPE_BYTE        PRIMITIVETYPE_BYTE
55 #define ARRAYTYPE_CHAR        PRIMITIVETYPE_CHAR
56 #define ARRAYTYPE_SHORT       PRIMITIVETYPE_SHORT
57 #define ARRAYTYPE_BOOLEAN     PRIMITIVETYPE_BOOLEAN
58 #define ARRAYTYPE_OBJECT      PRIMITIVETYPE_VOID     /* don't use as index! */
59
60
61 #ifdef __cplusplus
62
63 /**
64  * This is a generic accessor class for Java arrays (of unspecified type),
65  * which can be used to safely operate on Java arrays in native code.
66  */
67 class Array {
68 protected:
69         // Handle of Java array.
70         java_handle_array_t* _handle;
71
72 private:
73         // We don't want a Java arrays to be copied.
74         Array(Array* a) {}
75         Array(Array& a) {}
76
77 public:
78         Array(java_handle_t* h);
79         Array(int32_t length, classinfo* arrayclass);
80         virtual ~Array() {}
81
82         // Getters.
83         virtual java_handle_array_t* get_handle() const { return _handle; }
84         int32_t                      get_length() const;
85
86         // Null checks.
87         bool is_null    () const;
88         bool is_non_null() const;
89
90         // Safe element modification functions for primitive values
91         imm_union get_primitive_element(int32_t index);
92         void      set_primitive_element(int32_t index, imm_union value);
93
94         // Safe element modification functions for boxed values
95         java_handle_t* get_boxed_element(int32_t index);
96         void           set_boxed_element(int32_t index, java_handle_t *o);
97 };
98
99
100 /**
101  * Constructor checks if passed handle really is a Java array.
102  */
103 inline Array::Array(java_handle_t* h)
104 {
105         if (h == NULL) {
106                 _handle = NULL;
107                 return;
108         }
109
110 #if 0
111         classinfo* c;
112         LLNI_class_get(h, c);
113         if (!class_is_array(c)) {
114                 printf("Array::Array(): WARNING, passed handle is not an array\n");
115                 //exceptions_throw_illegalargumentexception("Argument is not an array");
116                 exceptions_throw_illegalargumentexception();
117                 _handle = NULL;
118                 return;
119         }
120 #endif
121
122         _handle = h;
123 }
124
125 /**
126  * Creates an array of the given array type on the heap.
127  * The handle pointer to the array can be NULL in case of an exception.
128  */
129 inline Array::Array(int32_t size, classinfo* arrayclass)
130 {
131         // Sanity check.
132         assert(class_is_array(arrayclass));
133
134         if (size < 0) {
135                 exceptions_throw_negativearraysizeexception();
136                 _handle = NULL;
137                 return;
138         }
139
140         arraydescriptor* desc          = arrayclass->vftbl->arraydesc;
141         int32_t          dataoffset    = desc->dataoffset;
142         int32_t          componentsize = desc->componentsize;
143         int32_t          actualsize    = dataoffset + size * componentsize;
144
145         // Check for overflow.
146
147         if (((u4) actualsize) < ((u4) size)) {
148                 exceptions_throw_outofmemoryerror();
149                 _handle = NULL;
150                 return;
151         }
152
153         java_array_t* a = (java_array_t*) heap_alloc(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL, true);
154
155         if (a == NULL) {
156                 _handle = NULL;
157                 return;
158         }
159
160         LLNI_vftbl_direct(a) = arrayclass->vftbl;
161
162 #if defined(ENABLE_THREADS)
163         a->objheader.lockword.init();
164 #endif
165
166         a->size = size;
167
168         _handle = (java_handle_array_t*) a;
169 }
170
171 inline int32_t Array::get_length() const
172 {
173         if (is_null()) {
174                 printf("Array::get_length(): WARNING, got null-pointer\n");
175                 exceptions_throw_nullpointerexception();
176                 return -1;
177         }
178
179         // XXX Fix me!
180         int32_t length = ((java_array_t*) _handle)->size;
181
182         return length;
183 }
184
185 inline bool Array::is_null() const
186 {
187         return (_handle == NULL);
188 }
189
190 inline bool Array::is_non_null() const
191 {
192         return (_handle != NULL);
193 }
194
195
196 /**
197  * This is a template of an accessor class for Java arrays
198  * of a specific type.
199  */
200 template<class T> class ArrayTemplate : public Array {
201 protected:
202         ArrayTemplate(int32_t length, classinfo* arrayclass) : Array(length, arrayclass) {}
203
204 public:
205         ArrayTemplate(java_handle_array_t* h) : Array(h) {}
206
207         // XXX This should be protected or private!
208         virtual T* get_raw_data_ptr() = 0;
209
210         // Safe element modification functions
211         T    get_element(int32_t index);
212         void set_element(int32_t index, T value);
213
214         // Region copy functions
215         void get_region(int32_t offset, int32_t count, T* buffer);
216         void set_region(int32_t offset, int32_t count, const T* buffer);
217 };
218
219
220 template<class T> inline T ArrayTemplate<T>::get_element(int32_t index)
221 {
222         if (is_null()) {
223                 exceptions_throw_nullpointerexception();
224                 return 0;
225         }
226
227         if ((index < 0) || (index >= get_length())) {
228                 exceptions_throw_arrayindexoutofboundsexception();
229                 return 0;
230         }
231
232         T* ptr = get_raw_data_ptr();
233
234         return ptr[index];
235 }
236
237 template<class T> inline void ArrayTemplate<T>::set_element(int32_t index, T value)
238 {
239         if (is_null()) {
240                 exceptions_throw_nullpointerexception();
241                 return;
242         }
243
244         if ((index < 0) || (index >= get_length())) {
245                 exceptions_throw_arrayindexoutofboundsexception();
246                 return;
247         }
248
249         T* ptr = get_raw_data_ptr();
250
251         ptr[index] = value;
252 }
253
254 template<> inline void ArrayTemplate<java_handle_t*>::set_element(int32_t index, java_handle_t* value)
255 {
256         if (is_null()) {
257                 exceptions_throw_nullpointerexception();
258                 return;
259         }
260
261         // Sanity check.
262         assert(((java_array_t*) get_handle())->objheader.vftbl->arraydesc->arraytype == ARRAYTYPE_OBJECT);
263
264         // Check if value can be stored
265         if (!builtin_canstore(get_handle(), value)) {
266                 exceptions_throw_illegalargumentexception();
267                 return;
268         }
269
270         if ((index < 0) || (index >= get_length())) {
271                 exceptions_throw_arrayindexoutofboundsexception();
272                 return;
273         }
274
275         java_handle_t** ptr = get_raw_data_ptr();
276
277         ptr[index] = value;
278 }
279
280 template<class T> inline void ArrayTemplate<T>::get_region(int32_t offset, int32_t count, T* buffer)
281 {
282         // Copy the array region inside a GC critical section.
283         GCCriticalSection cs;
284
285         const T* ptr = get_raw_data_ptr();
286
287         os::memcpy(buffer, ptr + offset, sizeof(T) * count);
288 }
289
290 template<class T> inline void ArrayTemplate<T>::set_region(int32_t offset, int32_t count, const T* buffer)
291 {
292         // Copy the array region inside a GC critical section.
293         GCCriticalSection cs;
294
295         T* ptr = get_raw_data_ptr();
296
297         os::memcpy(ptr + offset, buffer, sizeof(T) * count);
298 }
299
300
301 /**
302  * Actual implementations of common Java array access classes.
303  */
304 class BooleanArray : public ArrayTemplate<uint8_t> {
305 public:
306         BooleanArray(java_handle_booleanarray_t* h) : ArrayTemplate<uint8_t>(h) {}
307         BooleanArray(int32_t length) : ArrayTemplate<uint8_t>(length, primitivetype_table[ARRAYTYPE_BOOLEAN].arrayclass) {}
308         uint8_t* get_raw_data_ptr() { return ((java_booleanarray_t*) get_handle())->data; }
309 };
310
311 class ByteArray : public ArrayTemplate<int8_t> {
312 public:
313         ByteArray(java_handle_bytearray_t* h) : ArrayTemplate<int8_t>(h) {}
314         ByteArray(int32_t length) : ArrayTemplate<int8_t>(length, primitivetype_table[ARRAYTYPE_BYTE].arrayclass) {}
315         int8_t* get_raw_data_ptr() { return (int8_t*) ((java_bytearray_t*) get_handle())->data; }
316 };
317
318 class CharArray : public ArrayTemplate<uint16_t> {
319 public:
320         CharArray(java_handle_chararray_t* h) : ArrayTemplate<uint16_t>(h) {}
321         CharArray(int32_t length) : ArrayTemplate<uint16_t>(length, primitivetype_table[ARRAYTYPE_CHAR].arrayclass) {}
322         uint16_t* get_raw_data_ptr() { return ((java_chararray_t*) get_handle())->data; }
323 };
324
325 class ShortArray : public ArrayTemplate<int16_t> {
326 public:
327         ShortArray(java_handle_shortarray_t* h) : ArrayTemplate<int16_t>(h) {}
328         ShortArray(int32_t length) : ArrayTemplate<int16_t>(length, primitivetype_table[ARRAYTYPE_SHORT].arrayclass) {}
329         int16_t* get_raw_data_ptr() { return ((java_shortarray_t*) get_handle())->data; }
330 };
331
332 class IntArray : public ArrayTemplate<int32_t> {
333 public:
334         IntArray(java_handle_intarray_t* h) : ArrayTemplate<int32_t>(h) {}
335         IntArray(int32_t length) : ArrayTemplate<int32_t>(length, primitivetype_table[ARRAYTYPE_INT].arrayclass) {}
336         int32_t* get_raw_data_ptr() { return ((java_intarray_t*) get_handle())->data; }
337 };
338
339 class LongArray : public ArrayTemplate<int64_t> {
340 public:
341         LongArray(java_handle_longarray_t* h) : ArrayTemplate<int64_t>(h) {}
342         LongArray(int32_t length) : ArrayTemplate<int64_t>(length, primitivetype_table[ARRAYTYPE_LONG].arrayclass) {}
343         int64_t* get_raw_data_ptr() { return ((java_longarray_t*) get_handle())->data; }
344 };
345
346 class FloatArray : public ArrayTemplate<float> {
347 public:
348         FloatArray(java_handle_floatarray_t* h) : ArrayTemplate<float>(h) {}
349         FloatArray(int32_t length) : ArrayTemplate<float>(length, primitivetype_table[ARRAYTYPE_FLOAT].arrayclass) {}
350         float* get_raw_data_ptr() { return ((java_floatarray_t*) get_handle())->data; }
351 };
352
353 class DoubleArray : public ArrayTemplate<double> {
354 public:
355         DoubleArray(java_handle_doublearray_t* h) : ArrayTemplate<double>(h) {}
356         DoubleArray(int32_t length) : ArrayTemplate<double>(length, primitivetype_table[ARRAYTYPE_DOUBLE].arrayclass) {}
357         double* get_raw_data_ptr() { return ((java_doublearray_t*) get_handle())->data; }
358 };
359
360 /**
361  * Actual implementation of access class for Java Object arrays.
362  */
363 class ObjectArray : public ArrayTemplate<java_handle_t*> {
364 public:
365         ObjectArray(java_handle_objectarray_t* h) : ArrayTemplate<java_handle_t*>(h) {}
366         ObjectArray(int32_t length, classinfo* componentclass);
367         java_handle_t** get_raw_data_ptr() { return ((java_objectarray_t*) get_handle())->data; }
368 };
369
370 /**
371  * Actual implementation of access class for java.lang.Class arrays.
372  */
373 class ClassArray : public ArrayTemplate<classinfo*> {
374 public:
375         ClassArray(int32_t length);
376         classinfo** get_raw_data_ptr() { return (classinfo**) ((java_objectarray_t*) get_handle())->data; }
377 };
378
379
380 #else
381 # warning No legacy C functions for array access classes.
382 #endif
383
384 #endif // _VM_ARRAY_HPP
385
386
387 /*
388  * These are local overrides for various environment variables in Emacs.
389  * Please do not remove this and leave it at the end of the file, where
390  * Emacs will automagically detect them.
391  * ---------------------------------------------------------------------
392  * Local variables:
393  * mode: c++
394  * indent-tabs-mode: t
395  * c-basic-offset: 4
396  * tab-width: 4
397  * End:
398  * vim:noexpandtab:sw=4:ts=4:
399  */