According to the x86-64 ABI, we need to pass the first 6 INTEGER class arguments in specific registers and the rest on stack.
Signed-off-by: Eduard - Gabriel Munteanu <eduard.munte...@linux360.ro> --- arch/x86/Makefile_32 | 1 + arch/x86/Makefile_64 | 1 + arch/x86/args.c | 121 +++++++++++++++++++++++++++++++++++++ arch/x86/include/arch/args.h | 49 +++++++++++++++ arch/x86/include/arch/config_64.h | 2 + arch/x86/insn-selector.brg | 103 +++++++++++++++++++++++++++++++- include/jit/args.h | 10 +++- include/jit/expression.h | 1 + include/vm/method.h | 3 + jit/args.c | 33 +++++++++-- jit/invoke-bc.c | 6 +- jit/object-bc.c | 4 +- vm/method.c | 4 + 13 files changed, 327 insertions(+), 11 deletions(-) create mode 100644 arch/x86/args.c create mode 100644 arch/x86/include/arch/args.h diff --git a/arch/x86/Makefile_32 b/arch/x86/Makefile_32 index 71c9b85..ed00c94 100644 --- a/arch/x86/Makefile_32 +++ b/arch/x86/Makefile_32 @@ -1,4 +1,5 @@ ARCH_OBJS = \ + arch/x86/args.o \ arch/x86/backtrace.o \ arch/x86/disassemble.o \ arch/x86/emit-code.o \ diff --git a/arch/x86/Makefile_64 b/arch/x86/Makefile_64 index ab8c946..fed2c16 100644 --- a/arch/x86/Makefile_64 +++ b/arch/x86/Makefile_64 @@ -2,6 +2,7 @@ ARCH_INCLUDES = -I/usr/include/libffi ARCH_LIBS = -L/usr/lib64/libffi -lffi ARCH_OBJS = \ + arch/x86/args.o \ arch/x86/backtrace.o \ arch/x86/disassemble.o \ arch/x86/emit-code.o \ diff --git a/arch/x86/args.c b/arch/x86/args.c new file mode 100644 index 0000000..c52f3cd --- /dev/null +++ b/arch/x86/args.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2009 Eduard - Gabriel Munteanu <eduard.munte...@linux360.ro> + * + * This file is released under the GPL version 2 with the following + * clarification and special exception: + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under terms + * of your choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from or based on + * this library. If you modify this library, you may extend this exception + * to your version of the library, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. + * + * Please refer to the file LICENSE for details. + */ + +#include <assert.h> + +#include "arch/args.h" + +#include "jit/args.h" +#include "jit/expression.h" + +#include "vm/method.h" + +#ifdef CONFIG_X86_64 + +int args_init(unsigned long *state, + struct vm_method *method, + unsigned long nr_args) +{ + char *type; + + for (type = method->type; *type != ')'; type++) { + if (*type == 'I' || *type == 'L') { + method->args_count--; + method->reg_args_count++; + } + + if (method->reg_args_count == 6) + break; + } + + *state = 1; + + return 0; +} + +int args_set(unsigned long *state, + struct vm_method *method, + struct expression *expr) +{ + struct expression *value_expr = to_expr(expr->arg_expression); + unsigned long reg; + + if ((int) *state <= method->args_count) { + (*state)++; + expr->arg_private = NULL; + return 0; + } + + assert((value_expr->vm_type == J_INT || value_expr->vm_type == J_LONG)); + + reg = (6 - method->reg_args_count) + (*state)++ - method->args_count; + expr->arg_private = (void *) reg; + + return 0; +} + +static enum machine_reg __args_select_reg(unsigned long arg_idx) +{ + switch (arg_idx) { + case 0: + return REG_UNASSIGNED; + case 6: + return REG_RDI; + case 5: + return REG_RSI; + case 4: + return REG_RDX; + case 3: + return REG_RCX; + case 2: + return REG_R8; + case 1: + return REG_R9; + default: + assert(arg_idx > 6); + return REG_UNASSIGNED; + } +} + +enum machine_reg args_select_reg(struct expression *expr) +{ + return __args_select_reg((unsigned long) expr->arg_private); +} + +enum machine_reg args_local_to_reg(struct vm_method *method, int local_idx) +{ + local_idx++; + + /* Check if local_idx refers to *this or stack parameters. */ + if (local_idx > method->reg_args_count) + return REG_UNASSIGNED; + + return __args_select_reg(local_idx); +} + +#else /* CONFIG_X86_64 */ + +#endif /* CONFIG_X86_64 */ diff --git a/arch/x86/include/arch/args.h b/arch/x86/include/arch/args.h new file mode 100644 index 0000000..12b7efa --- /dev/null +++ b/arch/x86/include/arch/args.h @@ -0,0 +1,49 @@ +#ifndef __X86_ARGS_H +#define __X86_ARGS_H + +#include "arch/registers.h" + +#include "jit/expression.h" + +#include "vm/method.h" + +static inline void args_finish(unsigned long *state) +{ +} + +#ifdef CONFIG_X86_64 + +extern int args_init(unsigned long *state, + struct vm_method *method, + unsigned long nr_args); +extern int args_set(unsigned long *state, + struct vm_method *method, + struct expression *expr); +extern enum machine_reg args_select_reg(struct expression *expr); +extern enum machine_reg args_local_to_reg(struct vm_method *method, + int local_idx); + +static inline int args_stack_index(struct vm_method *method, int local_idx) +{ + return local_idx - method->reg_args_count; +} + +#else /* CONFIG_X86_64 */ + +static inline int args_init(unsigned long *state, + struct vm_method *method, + unsigned long nr_args) +{ + return 0; +} + +static inline int args_set(unsigned long *state, + struct vm_method *method, + struct expression *expr) +{ + return 0; +} + +#endif /* CONFIG_X86_64 */ + +#endif /* __X86_ARGS_H */ diff --git a/arch/x86/include/arch/config_64.h b/arch/x86/include/arch/config_64.h index bf8cb20..2e803fe 100644 --- a/arch/x86/include/arch/config_64.h +++ b/arch/x86/include/arch/config_64.h @@ -1,2 +1,4 @@ #define CONFIG_X86_64 1 #define USE_FFI 1 +#define CONFIG_REGPARM 1 + diff --git a/arch/x86/insn-selector.brg b/arch/x86/insn-selector.brg index ac34ec0..375b2ee 100644 --- a/arch/x86/insn-selector.brg +++ b/arch/x86/insn-selector.brg @@ -16,6 +16,7 @@ #include <jit/bc-offset-mapping.h> #include <jit/exception.h> +#include <arch/args.h> #include <arch/instruction.h> #include <arch/stack-frame.h> #include <arch/thread.h> @@ -74,7 +75,7 @@ static void method_args_cleanup(struct basic_block *bb, struct tree_node *tree, unsigned long args_size; stack_ptr = bb->b_parent->stack_ptr; - args_size = args_count * sizeof(uint32_t); + args_size = args_count * sizeof(long); select_insn(bb, tree, imm_reg_insn(INSN_ADD_IMM_REG, args_size, stack_ptr)); } @@ -199,6 +200,7 @@ reg: EXPR_VALUE 0 } } +%ifdef CONFIG_X86_32 reg: EXPR_LOCAL 1 { struct compilation_unit *cu = s->b_parent; @@ -223,6 +225,32 @@ reg: EXPR_LOCAL 1 select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, result)); } } +%else +reg: EXPR_LOCAL 1 +{ + struct compilation_unit *cu = s->b_parent; + struct expression *expr; + struct stack_slot *slot; + struct var_info *result; + enum machine_reg reg; + int index; + + expr = to_expr(tree); + slot = get_local_slot(cu->stack_frame, expr->local_index); + + reg = args_local_to_reg(s->b_parent->method, expr->local_index + 1); + if (reg == REG_UNASSIGNED) { + index = args_stack_index(cu->method, expr->local_index); + slot = get_local_slot(cu->stack_frame, index); + result = get_var(s->b_parent, J_LONG); + select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, + slot, result)); + } else + result = get_fixed_var(s->b_parent, reg); + + state->reg1 = result; +} +%endif freg: EXPR_LOCAL 0 { @@ -1275,6 +1303,7 @@ arg: EXPR_NO_ARGS state->reg1 = NULL; } +%ifdef CONFIG_X86_32 arg: EXPR_ARG(EXPR_VALUE) 1 { struct expression *expr, *arg_expr; @@ -1290,6 +1319,27 @@ arg: EXPR_ARG(EXPR_VALUE) 1 select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm & ~0UL)); } +%else +arg: EXPR_ARG(EXPR_VALUE) 1 +{ + struct expression *expr, *arg_expr; + enum machine_reg reg; + struct var_info *dst; + unsigned long imm; + + expr = to_expr(tree); + arg_expr = to_expr(expr->arg_expression); + imm = arg_expr->value; + + reg = args_select_reg(expr); + + if (reg != REG_UNASSIGNED) { + dst = get_fixed_var(s->b_parent, reg); + select_insn(s, tree, imm_reg_insn(INSN_MOV_IMM_REG, imm, dst)); + } else + select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm)); +} +%endif arg: EXPR_ARG(EXPR_FVALUE) 1 { @@ -1303,6 +1353,7 @@ arg: EXPR_ARG(EXPR_FVALUE) 1 select_insn(s, tree, imm_insn(INSN_PUSH_IMM, imm & ~0UL)); } +%ifdef CONFIG_X86_32 arg: EXPR_ARG(reg) { struct var_info *src; @@ -1321,6 +1372,28 @@ arg: EXPR_ARG(reg) state->reg1 = src; } +%else +arg: EXPR_ARG(reg) 1 +{ + struct var_info *src, *dst; + struct expression *expr, *arg_expr; + enum machine_reg reg; + + expr = to_expr(tree); + arg_expr = to_expr(expr->arg_expression); + + src = state->left->reg1; + + reg = args_select_reg(expr); + + if (reg != REG_UNASSIGNED) { + dst = get_fixed_var(s->b_parent, reg); + select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, dst)); + + } else + select_insn(s, tree, reg_insn(INSN_PUSH_REG, src)); +} +%endif arg: EXPR_ARGS_LIST(arg, arg) { @@ -1489,6 +1562,7 @@ stmt: STMT_STORE(EXPR_LOCAL, reg) } } +%ifdef CONFIG_X86_32 stmt: STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1 { struct expression *exprdest, *exprsrc; @@ -1512,6 +1586,33 @@ stmt: STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1 } } +%else +stmt: STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1 +{ + struct expression *exprdest, *exprsrc; + struct stack_slot *slot; + struct statement *stmt; + struct var_info *dest; + enum machine_reg reg; + int index; + + stmt = to_stmt(tree); + + exprsrc = to_expr(stmt->store_src); + exprdest = to_expr(stmt->store_dest); + + reg = args_local_to_reg(s->b_parent->method, exprsrc->local_index); + if (reg == REG_UNASSIGNED) { + index = args_stack_index(s->b_parent->method, + exprsrc->local_index); + slot = get_local_slot(s->b_parent->stack_frame, index); + dest = exprdest->tmp_low; + select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, + slot, dest)); + } else + exprdest->tmp_low = get_fixed_var(s->b_parent, reg); +} +%endif stmt: STMT_STORE(EXPR_TEMPORARY, reg) 1 { diff --git a/include/jit/args.h b/include/jit/args.h index 0339660..7ec20b7 100644 --- a/include/jit/args.h +++ b/include/jit/args.h @@ -3,10 +3,16 @@ #include "jit/expression.h" +#include "vm/method.h" #include "vm/stack.h" -struct expression *insert_arg(struct expression *root, struct expression *expr); -struct expression *convert_args(struct stack *mimic_stack, unsigned long nr_args); +struct expression *insert_arg(struct expression *root, + struct expression *expr, + unsigned long *args_state, + struct vm_method *method); +struct expression *convert_args(struct stack *mimic_stack, + unsigned long nr_args, + struct vm_method *method); const char *parse_method_args(const char *type_str, enum vm_type *vmtype); #endif diff --git a/include/jit/expression.h b/include/jit/expression.h index 86cd568..e029b3d 100644 --- a/include/jit/expression.h +++ b/include/jit/expression.h @@ -203,6 +203,7 @@ struct expression { instruction selection only. */ struct { struct tree_node *arg_expression; + void *arg_private; }; /* EXPR_NO_ARGS is used for EXPR_INVOKE expression type when diff --git a/include/vm/method.h b/include/vm/method.h index e86df11..18626b8 100644 --- a/include/vm/method.h +++ b/include/vm/method.h @@ -29,6 +29,9 @@ struct vm_method { char *name; char *type; int args_count; +#ifdef CONFIG_REGPARM + int reg_args_count; +#endif struct cafebabe_code_attribute code_attribute; struct cafebabe_line_number_table_attribute line_number_table_attribute; diff --git a/jit/args.c b/jit/args.c index 0680068..27d00bf 100644 --- a/jit/args.c +++ b/jit/args.c @@ -24,41 +24,64 @@ * Please refer to the file LICENSE for details. */ +#include <assert.h> + +#include "arch/args.h" + #include "jit/expression.h" #include "jit/args.h" +#include "vm/method.h" #include "vm/stack.h" struct expression * -insert_arg(struct expression *root, struct expression *expr) +insert_arg(struct expression *root, + struct expression *expr, + unsigned long *args_state, + struct vm_method *method) { struct expression *_expr; + int err; _expr = arg_expr(expr); _expr->bytecode_offset = expr->bytecode_offset; + if (args_state && method) { + err = args_set(args_state, method, _expr); + if (err) + return NULL; + } + if (!root) return _expr; return args_list_expr(root, _expr); } -struct expression * -convert_args(struct stack *mimic_stack, unsigned long nr_args) +struct expression *convert_args(struct stack *mimic_stack, + unsigned long nr_args, + struct vm_method *method) { struct expression *args_list = NULL; - unsigned long i; + unsigned long args_state, i; + int err; if (nr_args == 0) { args_list = no_args_expr(); goto out; } + err = args_init(&args_state, method, nr_args); + if (err) + return NULL; + for (i = 0; i < nr_args; i++) { struct expression *expr = stack_pop(mimic_stack); - args_list = insert_arg(args_list, expr); + args_list = insert_arg(args_list, expr, &args_state, method); } + args_finish(&args_state); + out: return args_list; } diff --git a/jit/invoke-bc.c b/jit/invoke-bc.c index 628ebf3..7441c64 100644 --- a/jit/invoke-bc.c +++ b/jit/invoke-bc.c @@ -72,7 +72,9 @@ static int convert_and_add_args(struct parse_context *ctx, { struct expression *args_list; - args_list = convert_args(ctx->bb->mimic_stack, method_real_argument_count(invoke_target)); + args_list = convert_args(ctx->bb->mimic_stack, + method_real_argument_count(invoke_target), + invoke_target); if (!args_list) return -ENOMEM; @@ -208,7 +210,7 @@ static void append_arg(struct expression *expr, struct expression *arg) { struct expression *args_list; - args_list = insert_arg(to_expr(expr->args_list), arg); + args_list = insert_arg(to_expr(expr->args_list), arg, NULL, NULL); expr->args_list = &args_list->node; } diff --git a/jit/object-bc.c b/jit/object-bc.c index e4eb12d..1252911 100644 --- a/jit/object-bc.c +++ b/jit/object-bc.c @@ -458,10 +458,12 @@ int convert_multianewarray(struct parse_context *ctx) unsigned long type_idx; unsigned char dimension; struct vm_class *class; + struct vm_method *method; type_idx = bytecode_read_u16(ctx->buffer); dimension = bytecode_read_u8(ctx->buffer); class = vm_class_resolve_class(ctx->cu->method->class, type_idx); + method = ctx->cu->method; if (!class) return -ENOMEM; @@ -469,7 +471,7 @@ int convert_multianewarray(struct parse_context *ctx) if (!arrayref) return -ENOMEM; - args_list = convert_args(ctx->bb->mimic_stack, dimension); + args_list = convert_args(ctx->bb->mimic_stack, dimension, method); size_check = multiarray_size_check_expr(args_list); if (!size_check) diff --git a/vm/method.c b/vm/method.c index 5a8b688..5727475 100644 --- a/vm/method.c +++ b/vm/method.c @@ -66,6 +66,10 @@ int vm_method_init(struct vm_method *vmm, return -1; } +#ifdef CONFIG_REGPARM + vmm->reg_args_count = 0; /* Updated later. */ +#endif + if (!vm_method_is_static(vmm)) ++vmm->args_count; -- 1.6.0.6 ------------------------------------------------------------------------------ Enter the BlackBerry Developer Challenge This is your chance to win up to $100,000 in prizes! For a limited time, vendors submitting new applications to BlackBerry App World(TM) will have the opportunity to enter the BlackBerry Developer Challenge. See full prize details at: http://p.sf.net/sfu/Challenge _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel