diff options
author | Pekka Enberg <penberg@kernel.org> | 2012-04-02 17:30:32 +0300 |
---|---|---|
committer | Pekka Enberg <penberg@kernel.org> | 2012-04-02 18:09:58 +0300 |
commit | 1421557342af2e4db5d29fb0d65396e8cff95dd5 (patch) | |
tree | 2c528991186a7a411045ec5274ba3385ca5a3707 | |
parent | dda8e18a46b4c7d2c5a1041c5e4a868af2a97133 (diff) | |
download | jato-1421557342af2e4db5d29fb0d65396e8cff95dd5.tar.gz |
jit: Fix argument register clobbering
This patch fixes a long-standing bug on x86-64 where arguments in register are
clobbered. The problem is visible in ParameterPassingLivenessTest which passes
with this patch applied.
Cc: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>
Cc: Tomek Grabiec <tgrabiec@gmail.com>
Cc: Vegard Nossum <vegardno@ifi.uio.no>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
-rw-r--r-- | include/jit/args.h | 3 | ||||
-rw-r--r-- | jit/args.c | 37 | ||||
-rw-r--r-- | jit/invoke-bc.c | 32 |
3 files changed, 61 insertions, 11 deletions
diff --git a/include/jit/args.h b/include/jit/args.h index fcaaab39..b527599a 100644 --- a/include/jit/args.h +++ b/include/jit/args.h @@ -8,7 +8,8 @@ #include <assert.h> -struct expression *convert_args(struct stack *mimic_stack, unsigned long nr_args, struct vm_method *method); +struct expression **pop_args(struct stack *mimic_stack, unsigned long nr_args); +struct expression *convert_args(struct expression **args_array, unsigned long nr_args, struct vm_method *method); struct expression *convert_native_args(struct stack *mimic_stack, unsigned long start_arg, unsigned long nr_args); #ifndef CONFIG_ARGS_MAP @@ -78,8 +78,36 @@ insert_arg(struct expression *root, struct expression *expr, struct vm_method *m return args_list_expr(root, _expr); } +struct expression **pop_args(struct stack *mimic_stack, unsigned long nr_args) +{ + struct expression **args_array; + unsigned long i; + + args_array = malloc(nr_args * sizeof(void *)); + if (!args_array) + return NULL; + + /* + * We scan the args map in reverse order, since the order of arguments + * is already reversed. + */ + for (i = 0; i < nr_args; i++) { + struct expression *expr = stack_pop(mimic_stack); + + args_array[i] = expr; + + if (vm_type_is_pair(expr->vm_type)) + i++; + + if (i >= nr_args) + break; + } + + return args_array; +} + struct expression * -convert_args(struct stack *mimic_stack, unsigned long nr_args, struct vm_method *method) +convert_args(struct expression **args_array, unsigned long nr_args, struct vm_method *method) { struct expression *args_list = NULL; unsigned long nr_total_args; @@ -99,12 +127,8 @@ convert_args(struct stack *mimic_stack, unsigned long nr_args, struct vm_method goto out; } - /* - * We scan the args map in reverse order, since the order of arguments - * is already reversed. - */ for (i = 0; i < nr_args; i++) { - struct expression *expr = stack_pop(mimic_stack); + struct expression *expr = args_array[i]; if (vm_type_is_pair(expr->vm_type)) i++; @@ -132,6 +156,7 @@ convert_args(struct stack *mimic_stack, unsigned long nr_args, struct vm_method * use method index zero here for JNI methods. */ } + out: return args_list; error: diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c index 17ae2c3c..d1709ad4 100644 --- a/jit/invoke-bc.c +++ b/jit/invoke-bc.c @@ -68,15 +68,39 @@ static int convert_and_add_args(struct parse_context *ctx, struct vm_method *invoke_target, struct statement *stmt) { + struct expression **args_array; struct expression *args_list; + unsigned long nr_args, i; - args_list = convert_args(ctx->bb->mimic_stack, - method_real_argument_count(invoke_target), - invoke_target); - if (!args_list) + nr_args = method_real_argument_count(invoke_target); + + args_array = pop_args(ctx->bb->mimic_stack, nr_args); + if (!args_array) return warn("out of memory"), -EINVAL; + for (i = 0; i < nr_args; i++) { + struct expression *expr = args_array[i]; + + if (!expr_is_pure(expr)) + args_array[i] = get_pure_expr(ctx, expr); + + if (vm_type_is_pair(expr->vm_type)) + i++; + + if (i >= nr_args) + break; + } + + args_list = convert_args(args_array, nr_args, invoke_target); + if (!args_list) { + free(args_array); + return warn("out of memory"), -EINVAL; + } + + free(args_array); + stmt->args_list = &args_list->node; + return 0; } |