instance of EXPR_ARRAY_DEREF that was connected to STMT_STORE and STMT_ARRAY_CHECK could have side effects. We must make sure that we create EXPR_ARRAY_DEREF with pure expressions as arrayref and index.
Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- jit/object-bc.c | 62 +++++++++++++++++++++++++++++++------------- test/jit/bc-test-utils.c | 4 +- test/jit/object-bc-test.c | 48 +++++++++++++++++++++++++++------- 3 files changed, 83 insertions(+), 31 deletions(-) diff --git a/jit/object-bc.c b/jit/object-bc.c index 76d5b1d..8b8658b 100644 --- a/jit/object-bc.c +++ b/jit/object-bc.c @@ -23,6 +23,20 @@ #include <string.h> #include <errno.h> +/** + * Returns a pure expression for given expression. If @expr is not + * pure we need to save it's value to a temporary and return the + * temporary. + */ +static struct expression * +get_pure_expr(struct parse_context *ctx, struct expression *expr) +{ + if (expr_is_pure(expr)) + return expr; + + return dup_expr(ctx, expr); +} + static char *class_name_to_array_name(const char *class_name) { char *array_name = malloc(strlen(class_name) + 4); @@ -158,23 +172,31 @@ int convert_putfield(struct parse_context *ctx) int convert_array_load(struct parse_context *ctx, enum vm_type type) { - struct expression *index, *arrayref, *arrayref_nullcheck; + struct expression *index, *arrayref; struct expression *src_expr, *dest_expr; struct statement *store_stmt, *arraycheck; struct var_info *temporary; + struct expression *arrayref_pure; + struct expression *index_pure; index = stack_pop(ctx->bb->mimic_stack); - arrayref = stack_pop(ctx->bb->mimic_stack); + arrayref = null_check_expr(stack_pop(ctx->bb->mimic_stack)); + if (!arrayref) + goto failed; store_stmt = alloc_statement(STMT_STORE); if (!store_stmt) goto failed; - arrayref_nullcheck = null_check_expr(arrayref); - if (!arrayref_nullcheck) - goto failed_arrayref_nullcheck; - - src_expr = array_deref_expr(type, arrayref_nullcheck, index); + /* + * We have to assure that arrayref and index expressions + * passed to array_deref_expr() do not have side effects + * because src_expr is connected to both STMT_STORE and + * STMT_ARRAY_CHECK. + */ + arrayref_pure = get_pure_expr(ctx, arrayref); + index_pure = get_pure_expr(ctx, index); + src_expr = array_deref_expr(type, arrayref_pure, index_pure); temporary = get_var(ctx->cu); dest_expr = temporary_expr(type, NULL, temporary); @@ -198,7 +220,6 @@ int convert_array_load(struct parse_context *ctx, enum vm_type type) return 0; failed_arraycheck: - failed_arrayref_nullcheck: free_statement(store_stmt); failed: return -ENOMEM; @@ -246,25 +267,30 @@ int convert_saload(struct parse_context *ctx) static int convert_array_store(struct parse_context *ctx, enum vm_type type) { - struct expression *value, *index, *arrayref, *arrayref_nullcheck; + struct expression *value, *index, *arrayref; struct statement *store_stmt, *arraycheck; struct statement *array_store_check_stmt; struct expression *src_expr, *dest_expr; + struct expression *arrayref_pure; + struct expression *index_pure; value = stack_pop(ctx->bb->mimic_stack); index = stack_pop(ctx->bb->mimic_stack); - arrayref = stack_pop(ctx->bb->mimic_stack); + + arrayref = null_check_expr(stack_pop(ctx->bb->mimic_stack)); + if (!arrayref) + goto failed; store_stmt = alloc_statement(STMT_STORE); if (!store_stmt) goto failed; - arrayref_nullcheck = null_check_expr(arrayref); - if (!arrayref_nullcheck) - goto failed_arrayref_nullcheck; - dest_expr = array_deref_expr(type, arrayref_nullcheck, index); - src_expr = value; + arrayref_pure = get_pure_expr(ctx, arrayref); + index_pure = get_pure_expr(ctx, index); + dest_expr = array_deref_expr(type, arrayref_pure, index_pure); + + src_expr = dup_expr(ctx, value); store_stmt->store_dest = &dest_expr->node; store_stmt->store_src = &src_expr->node; @@ -282,9 +308,8 @@ static int convert_array_store(struct parse_context *ctx, enum vm_type type) 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; - + expr_get(arrayref_pure); + array_store_check_stmt->store_check_array = &arrayref_pure->node; convert_statement(ctx, arraycheck); convert_statement(ctx, array_store_check_stmt); @@ -295,7 +320,6 @@ static int convert_array_store(struct parse_context *ctx, enum vm_type type) failed_array_store_check_stmt: free_statement(arraycheck); failed_arraycheck: - failed_arrayref_nullcheck: free_statement(store_stmt); failed: return -ENOMEM; diff --git a/test/jit/bc-test-utils.c b/test/jit/bc-test-utils.c index 12bbaf6..f2eb480 100644 --- a/test/jit/bc-test-utils.c +++ b/test/jit/bc-test-utils.c @@ -134,7 +134,7 @@ void assert_array_deref_expr(enum vm_type expected_vm_type, assert_int_equals(EXPR_ARRAY_DEREF, expr_type(expr)); assert_int_equals(expected_vm_type, expr->vm_type); - assert_null_check_expr(expected_arrayref, to_expr(expr->arrayref)); + assert_ptr_equals(expected_arrayref, to_expr(expr->arrayref)); assert_ptr_equals(expected_index, to_expr(expr->array_index)); } @@ -238,7 +238,7 @@ void assert_array_store_check_stmt(struct statement *stmt, 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(arrayref, to_expr(stmt->store_check_array)); assert_ptr_equals(store_src, stmt->store_check_src); } diff --git a/test/jit/object-bc-test.c b/test/jit/object-bc-test.c index 1569f08..f60f66c 100644 --- a/test/jit/object-bc-test.c +++ b/test/jit/object-bc-test.c @@ -247,13 +247,24 @@ static void assert_convert_array_load(enum vm_type expected_type, convert_to_ir(bb->b_parent); stmt = stmt_entry(bb->stmt_list.next); - struct statement *arraycheck = stmt; - struct statement *store_stmt = stmt_entry(arraycheck->stmt_list_node.next); + struct statement *arrayref_pure_stmt = stmt; + struct statement *arraycheck_stmt = stmt_entry(arrayref_pure_stmt->stmt_list_node.next); + struct statement *store_stmt = stmt_entry(arraycheck_stmt->stmt_list_node.next); - assert_arraycheck_stmt(expected_type, arrayref_expr, index_expr, arraycheck); + assert_store_stmt(arrayref_pure_stmt); + assert_nullcheck_value_expr(J_REFERENCE, arrayref, + arrayref_pure_stmt->store_src); + assert_temporary_expr(arrayref_pure_stmt->store_dest); + + assert_arraycheck_stmt(expected_type, + to_expr(arrayref_pure_stmt->store_dest), + index_expr, + arraycheck_stmt); assert_store_stmt(store_stmt); - assert_array_deref_expr(expected_type, arrayref_expr, index_expr, + assert_array_deref_expr(expected_type, + to_expr(arrayref_pure_stmt->store_dest), + index_expr, store_stmt->store_src); temporary_expr = stack_pop(bb->mimic_stack); @@ -342,16 +353,33 @@ static void assert_convert_array_store(enum vm_type expected_type, convert_to_ir(bb->b_parent); stmt = stmt_entry(bb->stmt_list.next); - struct statement *arraycheck = stmt; - struct statement *storecheck_stmt = stmt_entry(arraycheck->stmt_list_node.next); + struct statement *arrayref_pure_stmt = stmt; + struct statement *value_dup_stmt = stmt_entry(arrayref_pure_stmt->stmt_list_node.next); + struct statement *arraycheck_stmt = stmt_entry(value_dup_stmt->stmt_list_node.next); + struct statement *storecheck_stmt = stmt_entry(arraycheck_stmt->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, + assert_store_stmt(arrayref_pure_stmt); + assert_nullcheck_value_expr(J_REFERENCE, arrayref, + arrayref_pure_stmt->store_src); + assert_temporary_expr(arrayref_pure_stmt->store_dest); + + assert_store_stmt(value_dup_stmt); + assert_ptr_equals(&expr->node, value_dup_stmt->store_src); + assert_temporary_expr(value_dup_stmt->store_dest); + + assert_arraycheck_stmt(expected_type, + to_expr(arrayref_pure_stmt->store_dest), + index_expr, + arraycheck_stmt); + + assert_array_store_check_stmt(storecheck_stmt, + to_expr(arrayref_pure_stmt->store_dest), store_stmt->store_src); assert_store_stmt(store_stmt); - assert_array_deref_expr(expected_type, arrayref_expr, index_expr, + assert_array_deref_expr(expected_type, + to_expr(arrayref_pure_stmt->store_dest), + index_expr, store_stmt->store_dest); assert_temporary_expr(store_stmt->store_src); -- 1.6.0.6 ------------------------------------------------------------------------------ _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel