/* src/vm/array.hpp - Java array functions
- Copyright (C) 2007
+ Copyright (C) 2007, 2009
CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+ Copyright (C) 2008 Theobroma Systems Ltd.
This file is part of CACAO.
#include <stdint.h>
+#include "mm/gc.hpp" // XXX Remove me!
+
+#include "native/llni.h" // XXX Remove me!
+
+#include "vm/class.hpp"
+#include "vm/exceptions.hpp"
#include "vm/global.h"
#include "vm/primitive.hpp"
#define ARRAYTYPE_OBJECT PRIMITIVETYPE_VOID /* don't use as index! */
-/* function prototypes ********************************************************/
-
#ifdef __cplusplus
-extern "C" {
+
+/**
+ * This is a generic accessor class for Java arrays (of unspecified type),
+ * which can be used to safely operate on Java arrays in native code.
+ */
+class Array {
+protected:
+ // Handle of Java array.
+ java_handle_array_t* _handle;
+
+private:
+ // We don't want a Java arrays to be copied.
+ Array(Array* a) {}
+ Array(Array& a) {}
+
+public:
+ Array(java_handle_t* h);
+ Array(int32_t length, classinfo* arrayclass);
+ virtual ~Array() {}
+
+ // Getters.
+ virtual java_handle_array_t* get_handle() const { return _handle; }
+ int32_t get_length() const;
+
+ // Null checks.
+ bool is_null () const;
+ bool is_non_null() const;
+
+ // Safe element modification functions for primitive values
+ imm_union get_primitive_element(int32_t index);
+ void set_primitive_element(int32_t index, imm_union value);
+
+ // Safe element modification functions for boxed values
+ java_handle_t* get_boxed_element(int32_t index);
+ void set_boxed_element(int32_t index, java_handle_t *o);
+};
+
+
+/**
+ * Constructor checks if passed handle really is a Java array.
+ */
+inline Array::Array(java_handle_t* h)
+{
+ if (h == NULL) {
+ _handle = NULL;
+ return;
+ }
+
+#if 0
+ classinfo* c;
+ LLNI_class_get(h, c);
+ if (!class_is_array(c)) {
+ printf("Array::Array(): WARNING, passed handle is not an array\n");
+ //exceptions_throw_illegalargumentexception("Argument is not an array");
+ exceptions_throw_illegalargumentexception();
+ _handle = NULL;
+ return;
+ }
#endif
-java_handle_t *array_element_get(java_handle_t *a, int32_t index);
-void array_element_set(java_handle_t *a, int32_t index, java_handle_t *o);
-
-imm_union array_element_primitive_get(java_handle_t *a, int32_t index);
-void array_element_primitive_set(java_handle_t *a, int32_t index, imm_union value);
-
-uint8_t array_booleanarray_element_get(java_handle_booleanarray_t *a, int32_t index);
-int8_t array_bytearray_element_get(java_handle_bytearray_t *a, int32_t index);
-uint16_t array_chararray_element_get(java_handle_chararray_t *a, int32_t index);
-int16_t array_shortarray_element_get(java_handle_shortarray_t *a, int32_t index);
-int32_t array_intarray_element_get(java_handle_intarray_t *a, int32_t index);
-int64_t array_longarray_element_get(java_handle_longarray_t *a, int32_t index);
-float array_floatarray_element_get(java_handle_floatarray_t *a, int32_t index);
-double array_doublearray_element_get(java_handle_doublearray_t *a, int32_t index);
-java_handle_t *array_objectarray_element_get(java_handle_objectarray_t *a, int32_t index);
-
-void array_booleanarray_element_set(java_handle_booleanarray_t *a, int32_t index, uint8_t value);
-void array_bytearray_element_set(java_handle_bytearray_t *a, int32_t index, int8_t value);
-void array_chararray_element_set(java_handle_chararray_t *a, int32_t index, uint16_t value);
-void array_shortarray_element_set(java_handle_shortarray_t *a, int32_t index, int16_t value);
-void array_intarray_element_set(java_handle_intarray_t *a, int32_t index, int32_t value);
-void array_longarray_element_set(java_handle_longarray_t *a, int32_t index, int64_t value);
-void array_floatarray_element_set(java_handle_floatarray_t *a, int32_t index, float value);
-void array_doublearray_element_set(java_handle_doublearray_t *a, int32_t index, double value);
-void array_objectarray_element_set(java_handle_objectarray_t *a, int32_t index, java_handle_t *value);
-
-int32_t array_length_get(java_handle_t *a);
+ _handle = h;
+}
-#ifdef __cplusplus
-} // extern "C"
+/**
+ * Creates an array of the given array type on the heap.
+ * The handle pointer to the array can be NULL in case of an exception.
+ */
+inline Array::Array(int32_t size, classinfo* arrayclass)
+{
+ // Sanity check.
+ assert(class_is_array(arrayclass));
+
+ if (size < 0) {
+ exceptions_throw_negativearraysizeexception();
+ _handle = NULL;
+ return;
+ }
+
+ arraydescriptor* desc = arrayclass->vftbl->arraydesc;
+ int32_t dataoffset = desc->dataoffset;
+ int32_t componentsize = desc->componentsize;
+ int32_t actualsize = dataoffset + size * componentsize;
+
+ // Check for overflow.
+
+ if (((u4) actualsize) < ((u4) size)) {
+ exceptions_throw_outofmemoryerror();
+ _handle = NULL;
+ return;
+ }
+
+ java_array_t* a = (java_array_t*) heap_alloc(actualsize, (desc->arraytype == ARRAYTYPE_OBJECT), NULL, true);
+
+ if (a == NULL) {
+ _handle = NULL;
+ return;
+ }
+
+ LLNI_vftbl_direct(a) = arrayclass->vftbl;
+
+#if defined(ENABLE_THREADS)
+ a->objheader.lockword.init();
+#endif
+
+ a->size = size;
+
+ _handle = (java_handle_array_t*) a;
+}
+
+inline int32_t Array::get_length() const
+{
+ if (is_null()) {
+ printf("Array::get_length(): WARNING, got null-pointer\n");
+ exceptions_throw_nullpointerexception();
+ return -1;
+ }
+
+ // XXX Fix me!
+ int32_t length = ((java_array_t*) _handle)->size;
+
+ return length;
+}
+
+inline bool Array::is_null() const
+{
+ return (_handle == NULL);
+}
+
+inline bool Array::is_non_null() const
+{
+ return (_handle != NULL);
+}
+
+
+/**
+ * This is a template of an accessor class for Java arrays
+ * of a specific type.
+ */
+template<class T> class ArrayTemplate : public Array {
+protected:
+ ArrayTemplate(int32_t length, classinfo* arrayclass) : Array(length, arrayclass) {}
+
+public:
+ ArrayTemplate(java_handle_array_t* h) : Array(h) {}
+
+ // XXX This should be protected or private!
+ virtual T* get_raw_data_ptr() = 0;
+
+ // Safe element modification functions
+ T get_element(int32_t index);
+ void set_element(int32_t index, T value);
+
+ // Region copy functions
+ void get_region(int32_t offset, int32_t count, T* buffer);
+ void set_region(int32_t offset, int32_t count, const T* buffer);
+};
+
+
+template<class T> inline T ArrayTemplate<T>::get_element(int32_t index)
+{
+ if (is_null()) {
+ exceptions_throw_nullpointerexception();
+ return 0;
+ }
+
+ if ((index < 0) || (index >= get_length())) {
+ exceptions_throw_arrayindexoutofboundsexception();
+ return 0;
+ }
+
+ T* ptr = get_raw_data_ptr();
+
+ return ptr[index];
+}
+
+template<class T> inline void ArrayTemplate<T>::set_element(int32_t index, T value)
+{
+ if (is_null()) {
+ exceptions_throw_nullpointerexception();
+ return;
+ }
+
+ if ((index < 0) || (index >= get_length())) {
+ exceptions_throw_arrayindexoutofboundsexception();
+ return;
+ }
+
+ T* ptr = get_raw_data_ptr();
+
+ ptr[index] = value;
+}
+
+template<> inline void ArrayTemplate<java_handle_t*>::set_element(int32_t index, java_handle_t* value)
+{
+ if (is_null()) {
+ exceptions_throw_nullpointerexception();
+ return;
+ }
+
+ // Sanity check.
+ assert(((java_array_t*) get_handle())->objheader.vftbl->arraydesc->arraytype == ARRAYTYPE_OBJECT);
+
+ // Check if value can be stored
+ if (!builtin_canstore(get_handle(), value)) {
+ exceptions_throw_illegalargumentexception();
+ return;
+ }
+
+ if ((index < 0) || (index >= get_length())) {
+ exceptions_throw_arrayindexoutofboundsexception();
+ return;
+ }
+
+ java_handle_t** ptr = get_raw_data_ptr();
+
+ ptr[index] = value;
+}
+
+template<class T> inline void ArrayTemplate<T>::get_region(int32_t offset, int32_t count, T* buffer)
+{
+ // Copy the array region inside a GC critical section.
+ GCCriticalSection cs;
+
+ const T* ptr = get_raw_data_ptr();
+
+ os::memcpy(buffer, ptr + offset, sizeof(T) * count);
+}
+
+template<class T> inline void ArrayTemplate<T>::set_region(int32_t offset, int32_t count, const T* buffer)
+{
+ // Copy the array region inside a GC critical section.
+ GCCriticalSection cs;
+
+ T* ptr = get_raw_data_ptr();
+
+ os::memcpy(ptr + offset, buffer, sizeof(T) * count);
+}
+
+
+/**
+ * Actual implementations of common Java array access classes.
+ */
+class BooleanArray : public ArrayTemplate<uint8_t> {
+public:
+ BooleanArray(java_handle_booleanarray_t* h) : ArrayTemplate<uint8_t>(h) {}
+ BooleanArray(int32_t length) : ArrayTemplate<uint8_t>(length, primitivetype_table[ARRAYTYPE_BOOLEAN].arrayclass) {}
+ uint8_t* get_raw_data_ptr() { return ((java_booleanarray_t*) get_handle())->data; }
+};
+
+class ByteArray : public ArrayTemplate<int8_t> {
+public:
+ ByteArray(java_handle_bytearray_t* h) : ArrayTemplate<int8_t>(h) {}
+ ByteArray(int32_t length) : ArrayTemplate<int8_t>(length, primitivetype_table[ARRAYTYPE_BYTE].arrayclass) {}
+ int8_t* get_raw_data_ptr() { return (int8_t*) ((java_bytearray_t*) get_handle())->data; }
+};
+
+class CharArray : public ArrayTemplate<uint16_t> {
+public:
+ CharArray(java_handle_chararray_t* h) : ArrayTemplate<uint16_t>(h) {}
+ CharArray(int32_t length) : ArrayTemplate<uint16_t>(length, primitivetype_table[ARRAYTYPE_CHAR].arrayclass) {}
+ uint16_t* get_raw_data_ptr() { return ((java_chararray_t*) get_handle())->data; }
+};
+
+class ShortArray : public ArrayTemplate<int16_t> {
+public:
+ ShortArray(java_handle_shortarray_t* h) : ArrayTemplate<int16_t>(h) {}
+ ShortArray(int32_t length) : ArrayTemplate<int16_t>(length, primitivetype_table[ARRAYTYPE_SHORT].arrayclass) {}
+ int16_t* get_raw_data_ptr() { return ((java_shortarray_t*) get_handle())->data; }
+};
+
+class IntArray : public ArrayTemplate<int32_t> {
+public:
+ IntArray(java_handle_intarray_t* h) : ArrayTemplate<int32_t>(h) {}
+ IntArray(int32_t length) : ArrayTemplate<int32_t>(length, primitivetype_table[ARRAYTYPE_INT].arrayclass) {}
+ int32_t* get_raw_data_ptr() { return ((java_intarray_t*) get_handle())->data; }
+};
+
+class LongArray : public ArrayTemplate<int64_t> {
+public:
+ LongArray(java_handle_longarray_t* h) : ArrayTemplate<int64_t>(h) {}
+ LongArray(int32_t length) : ArrayTemplate<int64_t>(length, primitivetype_table[ARRAYTYPE_LONG].arrayclass) {}
+ int64_t* get_raw_data_ptr() { return ((java_longarray_t*) get_handle())->data; }
+};
+
+class FloatArray : public ArrayTemplate<float> {
+public:
+ FloatArray(java_handle_floatarray_t* h) : ArrayTemplate<float>(h) {}
+ FloatArray(int32_t length) : ArrayTemplate<float>(length, primitivetype_table[ARRAYTYPE_FLOAT].arrayclass) {}
+ float* get_raw_data_ptr() { return ((java_floatarray_t*) get_handle())->data; }
+};
+
+class DoubleArray : public ArrayTemplate<double> {
+public:
+ DoubleArray(java_handle_doublearray_t* h) : ArrayTemplate<double>(h) {}
+ DoubleArray(int32_t length) : ArrayTemplate<double>(length, primitivetype_table[ARRAYTYPE_DOUBLE].arrayclass) {}
+ double* get_raw_data_ptr() { return ((java_doublearray_t*) get_handle())->data; }
+};
+
+/**
+ * Actual implementation of access class for Java Object arrays.
+ */
+class ObjectArray : public ArrayTemplate<java_handle_t*> {
+public:
+ ObjectArray(java_handle_objectarray_t* h) : ArrayTemplate<java_handle_t*>(h) {}
+ ObjectArray(int32_t length, classinfo* componentclass);
+ java_handle_t** get_raw_data_ptr() { return ((java_objectarray_t*) get_handle())->data; }
+};
+
+/**
+ * Actual implementation of access class for java.lang.Class arrays.
+ */
+class ClassArray : public ArrayTemplate<classinfo*> {
+public:
+ ClassArray(int32_t length);
+ classinfo** get_raw_data_ptr() { return (classinfo**) ((java_objectarray_t*) get_handle())->data; }
+};
+
+
+#else
+# warning No legacy C functions for array access classes.
#endif
#endif // _VM_ARRAY_HPP