The purpose of this statement is to check whether the store source
is assignment compatible with array element type and throw
ArrayStoreException when this requirement is not met.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 arch/x86/insn-selector_32.brg |   21 ++++++++++++++++
 include/jit/statement.h       |    5 ++++
 include/vm/class.h            |    3 ++
 jit/object-bc.c               |   14 +++++++++++
 jit/statement.c               |    1 +
 jit/tree-printer.c            |   20 +++++++++++++++
 test/jamvm/class-stub.c       |    9 +++++++
 test/jit/bc-test-utils.c      |    9 +++++++
 test/jit/bc-test-utils.h      |    1 +
 test/jit/object-bc-test.c     |    6 +++-
 vm/class.c                    |   52 +++++++++++++++++++++++++++++++++++++++++
 11 files changed, 139 insertions(+), 2 deletions(-)

diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg
index 8a73256..9a698fa 100644
--- a/arch/x86/insn-selector_32.brg
+++ b/arch/x86/insn-selector_32.brg
@@ -1138,6 +1138,27 @@ stmt:    STMT_STORE(reg, array_deref)
        select_insn(s, tree, memindex_reg_insn(INSN_MOV_MEMINDEX_REG, base, 
index, scale, dest));
 }
 
+stmt:  STMT_ARRAY_STORE_CHECK(reg, reg) 1
+{
+       struct expression *src_expr;
+       struct statement *stmt;
+
+       stmt = to_stmt(tree);
+       src_expr = to_expr(stmt->store_check_src);
+
+       if (src_expr->vm_type == J_REFERENCE) {
+               select_insn(s, tree, reg_insn(INSN_PUSH_REG, 
state->left->reg1));
+               select_insn(s, tree, reg_insn(INSN_PUSH_REG, 
state->right->reg1));
+               select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
array_store_check));
+       } else {
+               select_insn(s, tree, reg_insn(INSN_PUSH_REG, 
state->left->reg1));
+               select_insn(s, tree, imm_insn(INSN_PUSH_IMM, 
src_expr->vm_type));
+               select_insn(s, tree, rel_insn(INSN_CALL_REL, (unsigned long) 
array_store_check_vmtype));
+       }
+
+       method_args_cleanup(s, tree, 2);
+}
+
 stmt:  STMT_ATHROW(reg)
 {
        struct var_info *reg_eax = get_fixed_var(s->b_parent, REG_EAX);
diff --git a/include/jit/statement.h b/include/jit/statement.h
index 99e84b1..b04737a 100644
--- a/include/jit/statement.h
+++ b/include/jit/statement.h
@@ -18,6 +18,7 @@ enum statement_type {
        STMT_MONITOR_ENTER,
        STMT_MONITOR_EXIT,
        STMT_CHECKCAST,
+       STMT_ARRAY_STORE_CHECK,
        STMT_LAST,      /* Not a real type. Keep this last.  */
 };
 
@@ -48,6 +49,10 @@ struct statement {
                struct /* STMT_ATHROW */ {
                        struct tree_node *exception_ref;
                };
+               struct /* STMT_ARRAY_STORE_CHECK */ {
+                       struct tree_node *store_check_src;
+                       struct tree_node *store_check_array;
+               };
                /* STMT_EXPRESSION, STMT_ARRAY_CHECK */
                struct tree_node *expression;
        };
diff --git a/include/vm/class.h b/include/vm/class.h
index 697dd9e..d78218b 100644
--- a/include/vm/class.h
+++ b/include/vm/class.h
@@ -1,11 +1,14 @@
 #ifndef __CLASS_H
 #define __CLASS_H
 
+#include <vm/types.h>
 #include <vm/vm.h>
 
 struct object *new_exception(char *class_name, char *message);
 unsigned long is_object_instance_of(struct object *obj, struct object *type);
 void check_array(struct object *obj, unsigned int index);
 void check_cast(struct object *obj, struct object *type);
+void array_store_check(struct object *arrayref, struct object *obj);
+void array_store_check_vmtype(struct object *arrayref, enum vm_type vm_type);
 
 #endif /* __CLASS_H */
diff --git a/jit/object-bc.c b/jit/object-bc.c
index ad8a6b9..a97a85f 100644
--- a/jit/object-bc.c
+++ b/jit/object-bc.c
@@ -247,6 +247,7 @@ static int convert_array_store(struct parse_context *ctx, 
enum vm_type type)
 {
        struct expression *value, *index, *arrayref, *arrayref_nullcheck;
        struct statement *store_stmt, *arraycheck;
+       struct statement *array_store_check_stmt;
        struct expression *src_expr, *dest_expr;
 
        value = stack_pop(ctx->bb->mimic_stack);
@@ -274,11 +275,24 @@ static int convert_array_store(struct parse_context *ctx, 
enum vm_type type)
        expr_get(dest_expr);
        arraycheck->expression = &dest_expr->node;
 
+       array_store_check_stmt = alloc_statement(STMT_ARRAY_STORE_CHECK);
+       if (!array_store_check_stmt)
+               goto failed_array_store_check_stmt;
+
+       expr_get(src_expr);
+       array_store_check_stmt->store_check_src = &src_expr->node;
+       expr_get(arrayref_nullcheck);
+       array_store_check_stmt->store_check_array = &arrayref_nullcheck->node;
+
+
        convert_statement(ctx, arraycheck);
+       convert_statement(ctx, array_store_check_stmt);
        convert_statement(ctx, store_stmt);
 
        return 0;
 
+      failed_array_store_check_stmt:
+       free_statement(arraycheck);
       failed_arraycheck:
       failed_arrayref_nullcheck:
        free_statement(store_stmt);
diff --git a/jit/statement.c b/jit/statement.c
index 34b2725..75b92be 100644
--- a/jit/statement.c
+++ b/jit/statement.c
@@ -33,6 +33,7 @@ void free_statement(struct statement *stmt)
 
        switch (stmt_type(stmt)) {
        case STMT_STORE:
+       case STMT_ARRAY_STORE_CHECK:
                expr_put(to_expr(stmt->store_dest));
                expr_put(to_expr(stmt->store_src));
                break;
diff --git a/jit/tree-printer.c b/jit/tree-printer.c
index 2257463..49c113b 100644
--- a/jit/tree-printer.c
+++ b/jit/tree-printer.c
@@ -268,6 +268,25 @@ static int print_athrow_stmt(int lvl, struct string *str,
        return err;
 }
 
+static int print_array_store_check_stmt(int lvl, struct string *str,
+                                       struct statement *stmt)
+{
+       int err;
+
+       err = append_formatted(lvl, str, "ARRAY_STORE_CHECK:\n");
+       if (err)
+               goto out;
+
+       err = append_tree_attr(lvl + 1, str, "src", stmt->store_check_src);
+       if (err)
+               goto out;
+
+       err = append_tree_attr(lvl + 1, str, "array", stmt->store_check_array);
+
+      out:
+       return err;
+}
+
 typedef int (*print_stmt_fn) (int, struct string * str, struct statement *);
 
 static print_stmt_fn stmt_printers[] = {
@@ -282,6 +301,7 @@ static print_stmt_fn stmt_printers[] = {
        [STMT_MONITOR_EXIT] = print_monitorexit_stmt,
        [STMT_CHECKCAST] = print_checkcast_stmt,
        [STMT_ATHROW] = print_athrow_stmt,
+       [STMT_ARRAY_STORE_CHECK] = print_array_store_check_stmt,
 };
 
 static int print_stmt(int lvl, struct tree_node *root, struct string *str)
diff --git a/test/jamvm/class-stub.c b/test/jamvm/class-stub.c
index cc28848..0ef5576 100644
--- a/test/jamvm/class-stub.c
+++ b/test/jamvm/class-stub.c
@@ -1,3 +1,4 @@
+#include <vm/types.h>
 #include <vm/vm.h>
 #include <stdlib.h>
 
@@ -33,3 +34,11 @@ void check_cast(struct object *obj, struct object *type)
        if (!isInstanceOf(type, obj->class))
                abort();
 }
+
+void array_store_check(struct object *arrayref, struct object *obj)
+{
+}
+
+void array_store_check_vmtype(struct object *arrayref, enum vm_type vm_type)
+{
+}
diff --git a/test/jit/bc-test-utils.c b/test/jit/bc-test-utils.c
index 5c9d3e4..54375f3 100644
--- a/test/jit/bc-test-utils.c
+++ b/test/jit/bc-test-utils.c
@@ -215,6 +215,15 @@ void assert_store_stmt(struct statement *stmt)
        assert_int_equals(STMT_STORE, stmt_type(stmt));
 }
 
+void assert_array_store_check_stmt(struct statement *stmt,
+                                  struct expression *arrayref,
+                                  struct tree_node *store_src)
+{
+       assert_int_equals(STMT_ARRAY_STORE_CHECK, stmt_type(stmt));
+       assert_null_check_expr(arrayref, to_expr(stmt->store_check_array));
+       assert_ptr_equals(store_src, stmt->store_check_src);
+}
+
 void assert_return_stmt(struct expression *return_value, struct statement 
*stmt)
 {
        assert_int_equals(STMT_RETURN, stmt_type(stmt));
diff --git a/test/jit/bc-test-utils.h b/test/jit/bc-test-utils.h
index b584c12..76324cc 100644
--- a/test/jit/bc-test-utils.h
+++ b/test/jit/bc-test-utils.h
@@ -38,6 +38,7 @@ void assert_invoke_expr(enum vm_type, struct methodblock *,
                        struct tree_node *);
 
 void assert_store_stmt(struct statement *);
+void assert_array_store_check_stmt(struct statement *, struct expression *, 
struct tree_node *);
 void assert_return_stmt(struct expression *, struct statement *);
 void assert_void_return_stmt(struct statement *);
 void assert_null_check_stmt(struct expression *, struct statement *);
diff --git a/test/jit/object-bc-test.c b/test/jit/object-bc-test.c
index 16c687a..d5c8976 100644
--- a/test/jit/object-bc-test.c
+++ b/test/jit/object-bc-test.c
@@ -335,11 +335,13 @@ static void assert_convert_array_store(enum vm_type 
expected_type,
        stmt = stmt_entry(bb->stmt_list.next);
 
        struct statement *arraycheck = stmt;
-       struct statement *store_stmt = 
stmt_entry(arraycheck->stmt_list_node.next);
+       struct statement *storecheck_stmt = 
stmt_entry(arraycheck->stmt_list_node.next);
+       struct statement *store_stmt = 
stmt_entry(storecheck_stmt->stmt_list_node.next);
 
        assert_arraycheck_stmt(expected_type, arrayref_expr, index_expr,
                               arraycheck);
-
+       assert_array_store_check_stmt(storecheck_stmt, arrayref_expr,
+                                     store_stmt->store_src);
        assert_store_stmt(store_stmt);
        assert_array_deref_expr(expected_type, arrayref_expr, index_expr,
                                store_stmt->store_dest);
diff --git a/vm/class.c b/vm/class.c
index 15fab23..3748f75 100644
--- a/vm/class.c
+++ b/vm/class.c
@@ -27,6 +27,7 @@
 #include <jit/exception.h>
 #include <jit/compiler.h>
 #include <vm/string.h>
+#include <vm/class.h>
 #include <vm/die.h>
 #include <vm/vm.h>
 #include <stdlib.h>
@@ -101,6 +102,57 @@ void check_array(struct object *obj, unsigned int index)
        throw_from_native(sizeof(struct object *) + sizeof(unsigned int));
 }
 
+void array_store_check(struct object *arrayref, struct object *obj)
+{
+       struct classblock *cb;
+       struct string *str;
+       int err;
+
+       cb = CLASS_CB(arrayref->class);
+
+       if (!IS_ARRAY(cb)) {
+               signal_new_exception("java/lang/RuntimeException",
+                                    "object is not an array");
+               goto throw;
+       }
+
+       if (obj == NULL || isInstanceOf(cb->element_class, obj->class))
+               return;
+
+       str = alloc_str();
+       if (str == NULL) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       err = str_append(str, slash2dots(CLASS_CB(obj->class)->name));
+       if (err)
+               goto error;
+
+       signal_new_exception("java/lang/ArrayStoreException", str->value);
+       free_str(str);
+
+ throw:
+       throw_from_native(2 * sizeof(struct object *));
+       return;
+
+ error:
+       if (str)
+               free_str(str);
+
+       if (err == -ENOMEM) /* TODO: throw OutOfMemoryError */
+               die("%s: out of memory", __func__);
+
+       die("%s: error %d", __func__, err);
+}
+
+void array_store_check_vmtype(struct object *arrayref, enum vm_type vm_type)
+{
+       /* TODO: Implement assignment compatibility checking described
+          in chapter "2.6.7 Assignment Conversion" of The Java VM
+          Specification - Second Edition. */
+}
+
 void check_cast(struct object *obj, struct object *type)
 {
        struct string *str;
-- 
1.6.0.6


------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables unlimited
royalty-free distribution of the report engine for externally facing 
server and web deployment.
http://p.sf.net/sfu/businessobjects
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to