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