aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPekka Enberg <penberg@kernel.org>2013-04-14 23:39:11 +0300
committerPekka Enberg <penberg@kernel.org>2013-04-15 21:33:03 +0300
commita048d852cac71dc4753288cfd5536560d7a2a9b9 (patch)
tree466c0200e8bf2845252eb9036e175d0979311584
parentc011aa175831dbd35cecb5be4d303d43854a09ad (diff)
downloadjato-a048d852cac71dc4753288cfd5536560d7a2a9b9.tar.gz
x86-64: Fix stack frame alignment for stack arguments
Section 3.2.2 ("The Stack Frame") of the SVR4 x86-64 ABI states that: The end of the input argument area shall be aligned on a 16 byte boundary. In other words, the value (%rsp - 8) is always a multiple of 16 when control is transferred to the function entry point. The stack pointer, %rsp, always points to the end of the latest allocated stack frame. Unfortunately the JIT compiler does not take that into account for arguments that are passed on the stack for x86-64. Fix the problem by adding a new STMT_BEFORE_ARGS statement that aligns the stack pointer properly and teach method_args_cleanup() to deal with the alignment. Signed-off-by: Pekka Enberg <penberg@kernel.org>
-rw-r--r--arch/x86/insn-selector_32.brg4
-rw-r--r--arch/x86/insn-selector_64.brg29
-rw-r--r--include/jit/statement.h3
-rw-r--r--jit/invoke-bc.c31
-rw-r--r--jit/statement.c1
-rw-r--r--jit/tree-printer.c18
6 files changed, 85 insertions, 1 deletions
diff --git a/arch/x86/insn-selector_32.brg b/arch/x86/insn-selector_32.brg
index 4b9f841b..beff0604 100644
--- a/arch/x86/insn-selector_32.brg
+++ b/arch/x86/insn-selector_32.brg
@@ -1547,6 +1547,10 @@ reg: EXPR_EXCEPTION_REF
select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, result));
}
+stmt: STMT_BEFORE_ARGS 1
+{
+}
+
stmt: STMT_INVOKE(arg) 1
{
invoke(s, tree);
diff --git a/arch/x86/insn-selector_64.brg b/arch/x86/insn-selector_64.brg
index 04d7b4f0..ce75c524 100644
--- a/arch/x86/insn-selector_64.brg
+++ b/arch/x86/insn-selector_64.brg
@@ -103,10 +103,16 @@ static void method_args_cleanup(struct basic_block *bb, struct tree_node *tree,
{
struct var_info *stack_ptr;
unsigned long args_size;
+ unsigned long unaligned;
stack_ptr = bb->b_parent->stack_ptr;
args_size = args_count * sizeof(long);
+ unaligned = args_size % X86_STACK_ALIGN;
+
+ if (unaligned)
+ args_size += X86_STACK_ALIGN - unaligned;
+
select_insn(bb, tree, imm_reg_insn(INSN_ADD_IMM_REG, args_size, stack_ptr));
}
@@ -1328,6 +1334,29 @@ reg: EXPR_EXCEPTION_REF
select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, result));
}
+stmt: STMT_BEFORE_ARGS 1
+{
+ struct compilation_unit *cu = s->b_parent;
+ struct var_info *stack_ptr;
+ struct vm_method *method;
+ unsigned long args_size;
+ unsigned long unaligned;
+ struct statement *stmt;
+ int nr_stack_args;
+
+ stmt = to_stmt(tree);
+ method = stmt->target_method;
+
+ nr_stack_args = get_stack_args_count(method);
+
+ stack_ptr = cu->stack_ptr;
+ args_size = nr_stack_args * sizeof(long);
+ unaligned = args_size % X86_STACK_ALIGN;
+
+ if (unaligned)
+ select_insn(s, tree, imm_reg_insn(INSN_SUB_IMM_REG, X86_STACK_ALIGN - unaligned, stack_ptr));
+}
+
stmt: STMT_INVOKE(arg) 1
{
select_insn(s, tree, insn(INSN_SAVE_CALLER_REGS));
diff --git a/include/jit/statement.h b/include/jit/statement.h
index 20b96adc..2647d36f 100644
--- a/include/jit/statement.h
+++ b/include/jit/statement.h
@@ -24,6 +24,7 @@ enum statement_type {
STMT_ARRAY_STORE_CHECK,
STMT_TABLESWITCH,
STMT_LOOKUPSWITCH_JUMP,
+ STMT_BEFORE_ARGS,
STMT_INVOKE,
STMT_INVOKEINTERFACE,
STMT_INVOKEVIRTUAL,
@@ -105,7 +106,7 @@ struct statement {
struct tree_node *lookupswitch_target;
};
- struct /* STMT_INVOKE, STMT_INVOKEVIRTUAL, STMT_INVOKEINTERFACE */ {
+ struct /* STMT_BEFORE_ARGS, STMT_INVOKE, STMT_INVOKEVIRTUAL, STMT_INVOKEINTERFACE */ {
struct tree_node *args_list;
struct vm_method *target_method;
};
diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c
index 4b708770..5c4fd447 100644
--- a/jit/invoke-bc.c
+++ b/jit/invoke-bc.c
@@ -198,6 +198,21 @@ static struct statement * invoke_stmt(struct parse_context *ctx,
return stmt;
}
+static int insert_before_args_stmt(struct parse_context *ctx, struct vm_method *target)
+{
+ struct statement *stmt;
+
+ stmt = alloc_statement(STMT_BEFORE_ARGS);
+ if (!stmt)
+ return warn("out of memory"), -ENOMEM;
+
+ stmt->target_method = target;
+
+ convert_statement(ctx, stmt);
+
+ return 0;
+}
+
static void insert_invoke_stmt(struct parse_context *ctx, struct statement *stmt)
{
convert_statement(ctx, stmt);
@@ -286,6 +301,10 @@ int convert_invokeinterface(struct parse_context *ctx)
if (err)
goto failed;
+ err = insert_before_args_stmt(ctx, invoke_target);
+ if (err)
+ goto failed;
+
insert_invoke_stmt(ctx, stmt);
return 0;
@@ -312,6 +331,10 @@ int convert_invokevirtual(struct parse_context *ctx)
if (err)
goto failed;
+ err = insert_before_args_stmt(ctx, invoke_target);
+ if (err)
+ goto failed;
+
insert_invoke_stmt(ctx, stmt);
return 0;
failed:
@@ -339,6 +362,10 @@ int convert_invokespecial(struct parse_context *ctx)
null_check_this_arg(to_expr(stmt->args_list));
+ err = insert_before_args_stmt(ctx, invoke_target);
+ if (err)
+ goto failed;
+
insert_invoke_stmt(ctx, stmt);
return 0;
failed:
@@ -364,6 +391,10 @@ int convert_invokestatic(struct parse_context *ctx)
if (err)
goto failed;
+ err = insert_before_args_stmt(ctx, invoke_target);
+ if (err)
+ goto failed;
+
insert_invoke_stmt(ctx, stmt);
return 0;
failed:
diff --git a/jit/statement.c b/jit/statement.c
index 60848a6f..9f944f48 100644
--- a/jit/statement.c
+++ b/jit/statement.c
@@ -38,6 +38,7 @@ int stmt_nr_kids(struct statement *stmt)
case STMT_INVOKEINTERFACE:
case STMT_INVOKEVIRTUAL:
return 1;
+ case STMT_BEFORE_ARGS:
case STMT_GOTO:
case STMT_VOID_RETURN:
return 0;
diff --git a/jit/tree-printer.c b/jit/tree-printer.c
index f0c30f12..5a5e2770 100644
--- a/jit/tree-printer.c
+++ b/jit/tree-printer.c
@@ -372,6 +372,23 @@ out:
return err;
}
+static int print_before_args_stmt(int lvl, struct string *str, struct statement *stmt)
+{
+ struct vm_method *method;
+ int err;
+
+ err = append_formatted(lvl, str, "BEFORE_ARGS:\n");
+ if (err)
+ goto out;
+
+ method = stmt->target_method;
+
+ err = append_simple_attr(lvl + 1, str, "target_method", "%p '%s.%s%s' (%lu)",
+ method, method->class->name, method->name, method->type, stmt_method_index(stmt));
+out:
+ return err;
+}
+
static int print_invoke_stmt(int lvl, struct string *str,
struct statement *stmt)
{
@@ -407,6 +424,7 @@ static print_stmt_fn stmt_printers[] = {
[STMT_ARRAY_STORE_CHECK] = print_array_store_check_stmt,
[STMT_TABLESWITCH] = print_tableswitch_stmt,
[STMT_LOOKUPSWITCH_JUMP] = print_lookupswitch_jump_stmt,
+ [STMT_BEFORE_ARGS] = print_before_args_stmt,
[STMT_INVOKE] = print_invoke_stmt,
[STMT_INVOKEINTERFACE] = print_invokeinterface_stmt,
[STMT_INVOKEVIRTUAL] = print_invokevirtual_stmt,