This refactoring introduces a general mechanism usable by other arches to provide argument passing in registers. Developers of other arches where this applies need only write a parser that allocates registers for arguments. The additional code and data structure support is controlled by CONFIG_ARGS_MAP.
Signed-off-by: Eduard - Gabriel Munteanu <eduard.munte...@linux360.ro> --- arch/x86/args.c | 144 +++++++++++++++++-------------------- arch/x86/include/arch/args.h | 63 ++++------------- arch/x86/include/arch/config_64.h | 2 +- arch/x86/insn-selector.brg | 51 +++++++------ include/jit/args.h | 20 +++++- include/jit/expression.h | 2 +- include/vm/method.h | 11 +++- jit/args.c | 61 ++++++++++------ vm/method.c | 11 ++- 9 files changed, 185 insertions(+), 180 deletions(-) rewrite arch/x86/include/arch/args.h (83%) diff --git a/arch/x86/args.c b/arch/x86/args.c index 715b38d..65d6522 100644 --- a/arch/x86/args.c +++ b/arch/x86/args.c @@ -26,25 +26,66 @@ #include <assert.h> #include <stdio.h> +#include <stdlib.h> #include "arch/args.h" #include "jit/args.h" -#include "jit/expression.h" #include "vm/method.h" #include "vm/types.h" #ifdef CONFIG_X86_64 -int args_init(unsigned long *state, - struct vm_method *method, - unsigned long nr_args) +static enum machine_reg args_map_alloc_gpr(int gpr) +{ + switch (gpr) { + case 0: + return REG_RDI; + case 1: + return REG_RSI; + case 2: + return REG_RDX; + case 3: + return REG_RCX; + case 4: + return REG_R8; + case 5: + return REG_R9; + default: + assert(gpr > 5); + return REG_UNASSIGNED; + } +} + +int args_map_init(struct vm_method *method) { const char *type; enum vm_type vm_type; - + int idx, gpr_count = 0, stack_count = 0; + struct vm_args_map *map; + size_t size; + + /* If the method isn't static, we have a *this. */ + size = method->args_count + !vm_method_is_static(method); + + method->args_map = malloc(sizeof(*map) * size); + if (!method->args_map) + return -1; + + /* We know *this is a J_REFERENCE, so allocate a GPR. */ + if (!vm_method_is_static(method)) { + map = &method->args_map[0]; + map->reg = args_map_alloc_gpr(gpr_count++); + map->stack_index = -1; + idx = 1; + } else + idx = 0; + + /* Scan the real parameters and assign registers and stack slots. */ for (type = method->type + 1; *type != ')'; skip_type(&type)) { + map = &method->args_map[idx]; + vm_type = str_to_type(type); switch (vm_type) { case J_BYTE: @@ -54,90 +95,39 @@ int args_init(unsigned long *state, case J_SHORT: case J_BOOLEAN: case J_REFERENCE: - method->reg_args_count++; + map->reg = args_map_alloc_gpr(gpr_count++); + map->stack_index = -1; + break; + case J_FLOAT: + case J_DOUBLE: + /* + * FIXME: This is wrong, but let's us + * not worry about the status of FP. + */ + map->reg = REG_UNASSIGNED; + map->stack_index = stack_count++; break; default: - NOT_IMPLEMENTED; + map->reg = REG_UNASSIGNED; + map->stack_index = stack_count++; break; } - if (method->reg_args_count == 6) + idx++; + + if (gpr_count == 6) break; } - if (vm_method_is_jni(method)) - method->reg_args_count += 2; - - method->reg_args_count = min(method->reg_args_count, 6); - method->args_count -= method->reg_args_count; + /* We're out of GPRs, so the remaining args go on the stack. */ + for (; idx < method->args_count; idx++) { + map = &method->args_map[idx]; - *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; + map->reg = REG_UNASSIGNED; + map->stack_index = stack_count++; } - assert((value_expr->vm_type == J_INT || - value_expr->vm_type == J_LONG || - value_expr->vm_type == J_REFERENCE)); - - 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 dissimilarity index 83% index 12b7efa..e3d3732 100644 --- a/arch/x86/include/arch/args.h +++ b/arch/x86/include/arch/args.h @@ -1,49 +1,14 @@ -#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 */ +#ifndef __X86_ARGS_H +#define __X86_ARGS_H + +#include "arch/registers.h" + +#include "vm/method.h" + +#ifdef CONFIG_X86_64 + +extern int args_map_init(struct vm_method *method); + +#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 80d752c..d15ae07 100644 --- a/arch/x86/include/arch/config_64.h +++ b/arch/x86/include/arch/config_64.h @@ -1,5 +1,5 @@ #define CONFIG_X86_64 1 #define CONFIG_64_BIT 1 #define USE_FFI 1 -#define CONFIG_REGPARM 1 +#define CONFIG_ARGS_MAP 1 diff --git a/arch/x86/insn-selector.brg b/arch/x86/insn-selector.brg index 516306e..231bf57 100644 --- a/arch/x86/insn-selector.brg +++ b/arch/x86/insn-selector.brg @@ -7,6 +7,7 @@ * LICENSE for details. */ +#include <jit/args.h> #include <jit/basic-block.h> #include <jit/compilation-unit.h> #include <jit/compiler.h> @@ -233,16 +234,18 @@ reg: EXPR_LOCAL 1 struct expression *expr; struct stack_slot *slot; struct var_info *result; + struct vm_method *method; 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); + method = cu->method; + + reg = method->args_map[expr->local_index].reg; if (reg == REG_UNASSIGNED) { - index = args_stack_index(cu->method, expr->local_index); - slot = get_local_slot(cu->stack_frame, index); + index = method->args_map[expr->local_index].stack_index; + slot = get_local_slot(s->b_parent->stack_frame, index); result = get_var(s->b_parent, J_LONG); select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, result)); @@ -636,6 +639,7 @@ reg: EXPR_INVOKEINTERFACE(arg) 1 unsigned long method_offset; struct vm_method *method; struct expression *expr; + int nr_stack_args; expr = to_expr(tree); method = expr->target_method; @@ -677,8 +681,9 @@ reg: EXPR_INVOKEINTERFACE(arg) 1 /* invoke method */ select_insn(s, tree, reg_insn(INSN_CALL_REG, call_target)); - if (method->args_count) - method_args_cleanup(s, tree, method->args_count); + nr_stack_args = get_stack_args_count(method); + if (nr_stack_args) + method_args_cleanup(s, tree, nr_stack_args); select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, eax, state->reg1)); if (edx != NULL) @@ -1283,7 +1288,6 @@ arg: EXPR_ARG(EXPR_VALUE) 1 arg: EXPR_ARG(EXPR_VALUE) 1 { struct expression *expr, *arg_expr; - enum machine_reg reg; struct var_info *dst; unsigned long imm; @@ -1291,10 +1295,8 @@ arg: EXPR_ARG(EXPR_VALUE) 1 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); + if (expr->arg_reg != REG_UNASSIGNED) { + dst = get_fixed_var(s->b_parent, expr->arg_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)); @@ -1337,17 +1339,14 @@ 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); + if (expr->arg_reg != REG_UNASSIGNED) { + dst = get_fixed_var(s->b_parent, expr->arg_reg); select_insn(s, tree, reg_reg_insn(INSN_MOV_REG_REG, src, dst)); state->reg1 = dst; } else { @@ -1573,6 +1572,7 @@ stmt: STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1 struct stack_slot *slot; struct statement *stmt; struct var_info *src, *dest; + struct vm_method *method; enum machine_reg reg; int index; @@ -1583,10 +1583,11 @@ stmt: STMT_STORE(EXPR_TEMPORARY, EXPR_LOCAL) 1 dest = exprdest->tmp_low; - reg = args_local_to_reg(s->b_parent->method, exprsrc->local_index); + method = s->b_parent->method; + + reg = method->args_map[exprsrc->local_index].reg; if (reg == REG_UNASSIGNED) { - index = args_stack_index(s->b_parent->method, - exprsrc->local_index); + index = method->args_map[exprsrc->local_index].stack_index; slot = get_local_slot(s->b_parent->stack_frame, index); select_insn(s, tree, memlocal_reg_insn(INSN_MOV_MEMLOCAL_REG, slot, dest)); @@ -2233,6 +2234,7 @@ static void invoke(struct basic_block *s, struct tree_node *tree, struct compila bool is_compiled; struct insn *call_insn; void *target; + int nr_stack_args; if (cu == s->b_parent) { /* @@ -2272,8 +2274,9 @@ static void invoke(struct basic_block *s, struct tree_node *tree, struct compila trampoline_add_fixup_site(method->trampoline, fixup); } - if (method->args_count) - method_args_cleanup(s, tree, method->args_count); + nr_stack_args = get_stack_args_count(method); + if (nr_stack_args) + method_args_cleanup(s, tree, nr_stack_args); if (vm_method_is_jni(method)) select_exception_test(s, tree); @@ -2287,6 +2290,7 @@ static void invokevirtual(struct _MBState *state, struct basic_block *s, struct struct var_info *call_target; unsigned long method_offset; struct vm_method *method; + int nr_stack_args; expr = to_expr(tree); method_offset = expr_method_index(expr) * sizeof(void *); @@ -2315,8 +2319,9 @@ static void invokevirtual(struct _MBState *state, struct basic_block *s, struct method = expr->target_method; - if (method->args_count) - method_args_cleanup(s, tree, method->args_count); + nr_stack_args = get_stack_args_count(method); + if (nr_stack_args) + method_args_cleanup(s, tree, nr_stack_args); } static void emit_code(struct basic_block *bb, MBState *state, int goal) diff --git a/include/jit/args.h b/include/jit/args.h index 7ec20b7..0047925 100644 --- a/include/jit/args.h +++ b/include/jit/args.h @@ -1,6 +1,8 @@ #ifndef __ARGS_H #define __ARGS_H +#include "arch/args.h" + #include "jit/expression.h" #include "vm/method.h" @@ -8,11 +10,25 @@ struct expression *insert_arg(struct expression *root, struct expression *expr, - unsigned long *args_state, - struct vm_method *method); + struct vm_method *method, + int index); 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); +#ifndef CONFIG_ARGS_MAP +static inline int args_map_init(struct vm_method *method) +{ + return 0; +} + +static inline int get_stack_args_count(struct vm_method *method) +{ + return method->args_count; +} +#else +extern int get_stack_args_count(struct vm_method *method); +#endif /* CONFIG_ARGS_MAP */ + #endif diff --git a/include/jit/expression.h b/include/jit/expression.h index e029b3d..be53649 100644 --- a/include/jit/expression.h +++ b/include/jit/expression.h @@ -203,7 +203,7 @@ struct expression { instruction selection only. */ struct { struct tree_node *arg_expression; - void *arg_private; + enum machine_reg arg_reg; }; /* EXPR_NO_ARGS is used for EXPR_INVOKE expression type when diff --git a/include/vm/method.h b/include/vm/method.h index c4ebff5..b246e64 100644 --- a/include/vm/method.h +++ b/include/vm/method.h @@ -19,6 +19,13 @@ struct vm_class; +#ifdef CONFIG_ARGS_MAP +struct vm_args_map { + int reg; + int stack_index; +}; +#endif + struct vm_method { struct vm_class *class; unsigned int method_index; @@ -29,8 +36,8 @@ struct vm_method { char *name; char *type; int args_count; -#ifdef CONFIG_REGPARM - int reg_args_count; +#ifdef CONFIG_ARGS_MAP + struct vm_args_map *args_map; #endif struct cafebabe_code_attribute code_attribute; diff --git a/jit/args.c b/jit/args.c index 3122e66..5c6ddaa 100644 --- a/jit/args.c +++ b/jit/args.c @@ -35,23 +35,43 @@ #include "vm/stack.h" #include "vm/jni.h" +#ifdef CONFIG_ARGS_MAP +int get_stack_args_count(struct vm_method *method) +{ + int i, count = 0; + + for (i = 0; i < method->args_count; i++) + if (method->args_map[i].reg == REG_UNASSIGNED) + count++; + + return count; +} + +static inline void set_expr_arg_reg(struct expression *expr, + struct vm_method *method, + int index) +{ + expr->arg_reg = method->args_map[index].reg; +} +#else /* CONFIG_ARGS_MAP */ +static void set_expr_arg_reg(struct expression *expr, + struct vm_method *method, + int index) +{ +} +#endif /* CONFIG_ARGS_MAP */ + struct expression * insert_arg(struct expression *root, struct expression *expr, - unsigned long *args_state, - struct vm_method *method) + struct vm_method *method, + int index) { 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; - } + set_expr_arg_reg(_expr, method, index); if (!root) return _expr; @@ -64,18 +84,13 @@ struct expression *convert_args(struct stack *mimic_stack, struct vm_method *method) { struct expression *args_list = NULL; - unsigned long args_state, i; - int err; + unsigned long i; if (nr_args == 0) { args_list = no_args_expr(); goto out; } - err = args_init(&args_state, method, nr_args); - if (err) - return NULL; - if (vm_method_is_jni(method)) { if (vm_method_is_static(method)) --nr_args; @@ -83,9 +98,14 @@ struct expression *convert_args(struct stack *mimic_stack, --nr_args; } + /* + * 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_list = insert_arg(args_list, expr, &args_state, method); + args_list = insert_arg(args_list, expr, + method, nr_args - i - 1); } if (vm_method_is_jni(method)) { @@ -102,8 +122,9 @@ struct expression *convert_args(struct stack *mimic_stack, return NULL; } + /* FIXME: Set index correctly */ args_list = insert_arg(args_list, class_expr, - &args_state, method); + method, 0); } jni_env_expr = value_expr(J_REFERENCE, @@ -113,12 +134,10 @@ struct expression *convert_args(struct stack *mimic_stack, return NULL; } - args_list = insert_arg(args_list, jni_env_expr, &args_state, - method); + /* FIXME: Set index correctly */ + args_list = insert_arg(args_list, jni_env_expr, method, 0); } - args_finish(&args_state); - out: return args_list; } diff --git a/vm/method.c b/vm/method.c index 37bd54d..ffdc021 100644 --- a/vm/method.c +++ b/vm/method.c @@ -1,5 +1,6 @@ #include <string.h> #include <stdio.h> +#include <stdlib.h> #include "cafebabe/attribute_array.h" #include "cafebabe/attribute_info.h" @@ -14,6 +15,7 @@ #include "vm/method.h" #include "vm/natives.h" +#include "jit/args.h" #include "jit/cu-mapping.h" int vm_method_init(struct vm_method *vmm, @@ -66,10 +68,6 @@ 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; @@ -87,6 +85,11 @@ int vm_method_init(struct vm_method *vmm, } } + if (args_map_init(vmm)) { + abort(); + return -1; + } + /* * Note: We can return here because the rest of the function deals * with loading attributes which native and abstract methods don't have. -- 1.6.0.6 ------------------------------------------------------------------------------ _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel