Fixes PR102 and PR119.
[cacao.git] / src / vm / primitive.cpp
index be03f75e035e68c7a29436e1e02fd289b3303061..388c08e2aa945e14d36db662e748568355999ed8 100644 (file)
 #include "native/llni.h"
 
 #include "vm/jit/builtin.hpp"
-#include "vm/class.h"
+#include "vm/class.hpp"
 #include "vm/global.h"
 #include "vm/globals.hpp"
 #include "vm/javaobjects.hpp"
 #include "vm/options.h"
+#include "vm/os.hpp"
 #include "vm/primitive.hpp"
 #include "vm/utf8.h"
-#include "vm/vm.hpp"
 
 
 /* primitivetype_table *********************************************************
@@ -412,7 +412,7 @@ java_handle_t* Primitive::box(int type, imm_union value)
                break;
        default:
                o = NULL;
-               VM::get_current()->abort("primitive_box: invalid primitive type %d", type);
+               os::abort("Primitive::box: Invalid primitive type %d", type);
        }
 
        return o;
@@ -473,13 +473,168 @@ imm_union Primitive::unbox(java_handle_t *h)
                value.a = h;
                break;
        default:
-               VM::get_current()->abort("Primitive::unbox: invalid primitive type %d", type);
+               os::abort("Primitive::unbox: Invalid primitive type %d", type);
        }
 
        return value;
 }
 
 
+/**
+ * Unbox a primitive of the given type. Also checks if the
+ * boxed primitive type can be widened into the destination
+ * type. This conversion is done according to
+ * "The Java Language Specification, Third Edition,
+ * $5.1.2 Widening Primitive Conversion".
+ *
+ * @param h Handle of the boxing Java object.
+ * @param type Destination type of the conversion.
+ * @param value Pointer to union where the resulting primitive
+ * value will be stored will.
+ *
+ * @return True of the conversion is allowed, false otherwise.
+ */
+bool Primitive::unbox_typed(java_handle_t *h, int type, imm_union* value)
+{
+       classinfo *c;
+       int        src_type;
+
+       if (h == NULL)
+               return false;
+
+       LLNI_class_get(h, c);
+
+       src_type = get_type_by_wrapperclass(c);
+
+       switch (src_type) {
+       case PRIMITIVETYPE_BOOLEAN:
+               switch (type) {
+                       case PRIMITIVETYPE_BOOLEAN:
+                               value->i = unbox_boolean(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       case PRIMITIVETYPE_BYTE:
+               switch (type) {
+                       case PRIMITIVETYPE_BYTE:
+                       case PRIMITIVETYPE_SHORT:
+                       case PRIMITIVETYPE_INT:
+                               value->i = unbox_byte(h);
+                               return true;
+                       case PRIMITIVETYPE_LONG:
+                               value->l = unbox_byte(h);
+                               return true;
+                       case PRIMITIVETYPE_FLOAT:
+                               value->f = unbox_byte(h);
+                               return true;
+                       case PRIMITIVETYPE_DOUBLE:
+                               value->d = unbox_byte(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       case PRIMITIVETYPE_CHAR:
+               switch (type) {
+                       case PRIMITIVETYPE_CHAR:
+                       case PRIMITIVETYPE_INT:
+                               value->i = unbox_char(h);
+                               return true;
+                       case PRIMITIVETYPE_LONG:
+                               value->l = unbox_char(h);
+                               return true;
+                       case PRIMITIVETYPE_FLOAT:
+                               value->f = unbox_char(h);
+                               return true;
+                       case PRIMITIVETYPE_DOUBLE:
+                               value->d = unbox_char(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       case PRIMITIVETYPE_SHORT:
+               switch (type) {
+                       case PRIMITIVETYPE_SHORT:
+                       case PRIMITIVETYPE_INT:
+                               value->i = unbox_short(h);
+                               return true;
+                       case PRIMITIVETYPE_LONG:
+                               value->l = unbox_short(h);
+                               return true;
+                       case PRIMITIVETYPE_FLOAT:
+                               value->f = unbox_short(h);
+                               return true;
+                       case PRIMITIVETYPE_DOUBLE:
+                               value->d = unbox_short(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       case PRIMITIVETYPE_INT:
+               switch (type) {
+                       case PRIMITIVETYPE_INT:
+                               value->i = unbox_int(h);
+                               return true;
+                       case PRIMITIVETYPE_LONG:
+                               value->l = unbox_int(h);
+                               return true;
+                       case PRIMITIVETYPE_FLOAT:
+                               value->f = unbox_int(h);
+                               return true;
+                       case PRIMITIVETYPE_DOUBLE:
+                               value->d = unbox_int(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       case PRIMITIVETYPE_LONG:
+               switch (type) {
+                       case PRIMITIVETYPE_LONG:
+                               value->l = unbox_long(h);
+                               return true;
+                       case PRIMITIVETYPE_FLOAT:
+                               value->f = unbox_long(h);
+                               return true;
+                       case PRIMITIVETYPE_DOUBLE:
+                               value->d = unbox_long(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       case PRIMITIVETYPE_FLOAT:
+               switch (type) {
+                       case PRIMITIVETYPE_FLOAT:
+                               value->f = unbox_float(h);
+                               return true;
+                       case PRIMITIVETYPE_DOUBLE:
+                               value->d = unbox_float(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       case PRIMITIVETYPE_DOUBLE:
+               switch (type) {
+                       case PRIMITIVETYPE_DOUBLE:
+                               value->d = unbox_double(h);
+                               return true;
+                       default:
+                               return false;
+               }
+
+       default:
+               os::abort("Primitive::unbox_typed: Invalid primitive type %d", type);
+               return false;
+       }
+}
+
+
 /**
  * Box a primitive type.
  */
@@ -652,13 +807,9 @@ inline double Primitive::unbox_double(java_handle_t *h)
 
 extern "C" {
 
-       classinfo* Primitive_get_class_by_name(utf *name) { return Primitive::get_class_by_name(name); }
+classinfo* Primitive_get_class_by_name(utf *name) { return Primitive::get_class_by_name(name); }
 classinfo* Primitive_get_class_by_type(int type) { return Primitive::get_class_by_type(type); }
-classinfo* Primitive_get_arrayclass_by_name(utf *name) { return Primitive::get_arrayclass_by_name(name); }
 classinfo* Primitive_get_arrayclass_by_type(int type) { return Primitive::get_arrayclass_by_type(type); }
-int Primitive_get_type_by_wrapperclass(classinfo *c) { return Primitive::get_type_by_wrapperclass(c); }
-java_handle_t* Primitive_box(int type, imm_union value) { return Primitive::box(type, value); }
-imm_union Primitive_unbox(java_handle_t *h) { return Primitive::unbox(h); }
 }