📄 jcf-write.c
字号:
/* Generate bytecode for sub-expression EXP of METHOD. TARGET is one of STACK_TARGET or IGNORE_TARGET. */static voidgenerate_bytecode_insns (exp, target, state) tree exp; int target; struct jcf_partial *state;{ tree type; enum java_opcode jopcode; int op; HOST_WIDE_INT value; int post_op; int size; int offset; if (exp == NULL && target == IGNORE_TARGET) return; type = TREE_TYPE (exp); switch (TREE_CODE (exp)) { case BLOCK: if (BLOCK_EXPR_BODY (exp)) { tree local; tree body = BLOCK_EXPR_BODY (exp); for (local = BLOCK_EXPR_DECLS (exp); local; ) { tree next = TREE_CHAIN (local); localvar_alloc (local, state); local = next; } /* Avoid deep recursion for long blocks. */ while (TREE_CODE (body) == COMPOUND_EXPR) { generate_bytecode_insns (TREE_OPERAND (body, 0), target, state); body = TREE_OPERAND (body, 1); } generate_bytecode_insns (body, target, state); for (local = BLOCK_EXPR_DECLS (exp); local; ) { tree next = TREE_CHAIN (local); localvar_free (local, state); local = next; } } break; case COMPOUND_EXPR: generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state); generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state); break; case EXPR_WITH_FILE_LOCATION: { char *saved_input_filename = input_filename; tree body = EXPR_WFL_NODE (exp); int saved_lineno = lineno; if (body == empty_stmt_node) break; input_filename = EXPR_WFL_FILENAME (exp); lineno = EXPR_WFL_LINENO (exp); if (EXPR_WFL_EMIT_LINE_NOTE (exp) && lineno > 0 && debug_info_level > DINFO_LEVEL_NONE) put_linenumber (lineno, state); generate_bytecode_insns (body, target, state); input_filename = saved_input_filename; lineno = saved_lineno; } break; case INTEGER_CST: if (target == IGNORE_TARGET) ; /* do nothing */ else if (TREE_CODE (type) == POINTER_TYPE) { if (! integer_zerop (exp)) abort(); RESERVE(1); OP1 (OPCODE_aconst_null); NOTE_PUSH (1); } else if (TYPE_PRECISION (type) <= 32) { push_int_const (TREE_INT_CST_LOW (exp), state); NOTE_PUSH (1); } else { push_long_const (TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp), state); NOTE_PUSH (2); } break; case REAL_CST: { int prec = TYPE_PRECISION (type) >> 5; RESERVE(1); if (real_zerop (exp)) OP1 (prec == 1 ? OPCODE_fconst_0 : OPCODE_dconst_0); else if (real_onep (exp)) OP1 (prec == 1 ? OPCODE_fconst_1 : OPCODE_dconst_1); /* FIXME Should also use fconst_2 for 2.0f. Also, should use iconst_2/ldc followed by i2f/i2d for other float/double when the value is a small integer. */ else { offset = find_constant_index (exp, state); if (prec == 1) push_constant1 (offset, state); else push_constant2 (offset, state); } NOTE_PUSH (prec); } break; case STRING_CST: push_constant1 (find_string_constant (&state->cpool, exp), state); NOTE_PUSH (1); break; case VAR_DECL: if (TREE_STATIC (exp)) { field_op (exp, OPCODE_getstatic, state); NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1); break; } /* ... fall through ... */ case PARM_DECL: emit_load (exp, state); break; case NON_LVALUE_EXPR: case INDIRECT_REF: generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); break; case ARRAY_REF: generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state); if (target != IGNORE_TARGET) { jopcode = OPCODE_iaload + adjust_typed_op (type, 7); RESERVE(1); OP1 (jopcode); if (! TYPE_IS_WIDE (type)) NOTE_POP (1); } break; case COMPONENT_REF: { tree obj = TREE_OPERAND (exp, 0); tree field = TREE_OPERAND (exp, 1); int is_static = FIELD_STATIC (field); generate_bytecode_insns (obj, is_static ? IGNORE_TARGET : target, state); if (target != IGNORE_TARGET) { if (DECL_NAME (field) == length_identifier_node && !is_static && TYPE_ARRAY_P (TREE_TYPE (obj))) { RESERVE (1); OP1 (OPCODE_arraylength); } else { field_op (field, is_static ? OPCODE_getstatic : OPCODE_getfield, state); if (! is_static) NOTE_POP (1); NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1); } } } break; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case EQ_EXPR: case NE_EXPR: case GT_EXPR: case LT_EXPR: case GE_EXPR: case LE_EXPR: { struct jcf_block *then_label = gen_jcf_label (state); struct jcf_block *else_label = gen_jcf_label (state); struct jcf_block *end_label = gen_jcf_label (state); generate_bytecode_conditional (exp, then_label, else_label, 1, state); define_jcf_label (then_label, state); push_int_const (1, state); emit_goto (end_label, state); define_jcf_label (else_label, state); push_int_const (0, state); define_jcf_label (end_label, state); NOTE_PUSH (1); } break; case COND_EXPR: { struct jcf_block *then_label = gen_jcf_label (state); struct jcf_block *else_label = gen_jcf_label (state); struct jcf_block *end_label = gen_jcf_label (state); generate_bytecode_conditional (TREE_OPERAND (exp, 0), then_label, else_label, 1, state); define_jcf_label (then_label, state); generate_bytecode_insns (TREE_OPERAND (exp, 1), target, state); if (CAN_COMPLETE_NORMALLY (TREE_OPERAND (exp, 1)) /* Not all expressions have CAN_COMPLETE_NORMALLY set properly. */ || TREE_CODE (TREE_TYPE (exp)) != VOID_TYPE) emit_goto (end_label, state); define_jcf_label (else_label, state); generate_bytecode_insns (TREE_OPERAND (exp, 2), target, state); define_jcf_label (end_label, state); } break; case CASE_EXPR: { struct jcf_switch_state *sw_state = state->sw_state; struct jcf_relocation *reloc = (struct jcf_relocation *) obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); HOST_WIDE_INT case_value = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0)); reloc->kind = 0; reloc->label = get_jcf_label_here (state); reloc->offset = case_value; reloc->next = sw_state->cases; sw_state->cases = reloc; if (sw_state->num_cases == 0) { sw_state->min_case = case_value; sw_state->max_case = case_value; } else { if (case_value < sw_state->min_case) sw_state->min_case = case_value; if (case_value > sw_state->max_case) sw_state->max_case = case_value; } sw_state->num_cases++; } break; case DEFAULT_EXPR: state->sw_state->default_label = get_jcf_label_here (state); break; case SWITCH_EXPR: { /* The SWITCH_EXPR has three parts, generated in the following order: 1. the switch_expression (the value used to select the correct case); 2. the switch_body; 3. the switch_instruction (the tableswitch/loopupswitch instruction.). After code generation, we will re-order then in the order 1, 3, 2. This is to avoid an extra GOTOs. */ struct jcf_switch_state sw_state; struct jcf_block *expression_last; /* Last block of the switch_expression. */ struct jcf_block *body_last; /* Last block of the switch_body. */ struct jcf_block *switch_instruction; /* First block of switch_instruction. */ struct jcf_block *instruction_last; /* Last block of the switch_instruction. */ struct jcf_block *body_block; int switch_length; sw_state.prev = state->sw_state; state->sw_state = &sw_state; sw_state.cases = NULL; sw_state.num_cases = 0; sw_state.default_label = NULL; generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state); expression_last = state->last_block; body_block = get_jcf_label_here (state); /* Force a new block here. */ generate_bytecode_insns (TREE_OPERAND (exp, 1), IGNORE_TARGET, state); body_last = state->last_block; switch_instruction = gen_jcf_label (state); define_jcf_label (switch_instruction, state); if (sw_state.default_label == NULL) sw_state.default_label = gen_jcf_label (state); if (sw_state.num_cases <= 1) { if (sw_state.num_cases == 0) { emit_pop (1, state); NOTE_POP (1); } else { push_int_const (sw_state.cases->offset, state); emit_if (sw_state.cases->label, OPCODE_ifeq, OPCODE_ifne, state); } emit_goto (sw_state.default_label, state); } else { HOST_WIDE_INT i; /* Copy the chain of relocs into a sorted array. */ struct jcf_relocation **relocs = (struct jcf_relocation **) xmalloc (sw_state.num_cases * sizeof (struct jcf_relocation *)); /* The relocs arrays is a buffer with a gap. The assumption is that cases will normally come in "runs". */ int gap_start = 0; int gap_end = sw_state.num_cases; struct jcf_relocation *reloc; for (reloc = sw_state.cases; reloc != NULL; reloc = reloc->next) { HOST_WIDE_INT case_value = reloc->offset; while (gap_end < sw_state.num_cases) { struct jcf_relocation *end = relocs[gap_end]; if (case_value <= end->offset) break; relocs[gap_start++] = end; gap_end++; } while (gap_start > 0) { struct jcf_relocation *before = relocs[gap_start-1]; if (case_value >= before->offset) break; relocs[--gap_end] = before; gap_start--; } relocs[gap_start++] = reloc; /* Note we don't check for duplicates. FIXME! */ } if (2 * sw_state.num_cases >= sw_state.max_case - sw_state.min_case) { /* Use tableswitch. */ int index = 0; RESERVE (13 + 4 * (sw_state.max_case - sw_state.min_case + 1)); OP1 (OPCODE_tableswitch); emit_reloc (0, SWITCH_ALIGN_RELOC, NULL, state); emit_switch_reloc (sw_state.default_label, state); OP4 (sw_state.min_case); OP4 (sw_state.max_case); for (i = sw_state.min_case; ; ) { reloc = relocs[index]; if (i == reloc->offset) { emit_case_reloc (reloc, state); if (i == sw_state.max_case) break; index++; } else emit_switch_reloc (sw_state.default_label, state); i++; } } else { /* Use lookupswitch. */ RESERVE(9 + 8 * sw_state.num_cases); OP1 (OPCODE_lookupswitch); emit_reloc (0, SWITCH_ALIGN_RELOC, NULL, state); emit_switch_reloc (sw_state.default_label, state); OP4 (sw_state.num_cases); for (i = 0; i < sw_state.num_cases; i++) { struct jcf_relocation *reloc = relocs[i]; OP4 (reloc->offset); emit_case_reloc (reloc, state); } } free (relocs); } instruction_last = state->last_block; if (sw_state.default_label->pc < 0) define_jcf_label (sw_state.default_label, state); else /* Force a new block. */ sw_state.default_label = get_jcf_label_here (state); /* Now re-arrange the blocks so the switch_instruction comes before the switch_body. */ switch_length = state->code_length - switch_instruction->pc; switch_instruction->pc = body_block->pc; instruction_last->next = body_block; instruction_last->v.chunk->next = body_block->v.chunk; expression_last->next = switch_instruction; expression_last->v.chunk->next = switch_instruction->v.chunk; body_last->next = sw_state.default_label; body_last->v.chunk->next = NULL; state->chunk = body_last->v.chunk; for (; body_block != sw_state.default_label; body_block = body_block->next) body_block->pc += switch_length; state->sw_state = sw_state.prev; break; } case RETURN_EXPR: exp = TREE_OPERAND (exp, 0); if (exp == NULL_TREE) exp = empty_stmt_node; else if (TREE_CODE (exp) != MODIFY_EXPR) abort (); else exp = TREE_OPERAND (exp, 1); generate_bytecode_return (exp, state); break; case LABELED_BLOCK_EXPR: { struct jcf_block *end_label = gen_jcf_label (state); end_label->next = state->labeled_blocks; state->labeled_blocks = end_label; end_label->pc = PENDING_EXIT_PC; end_label->u.labeled_block = exp; if (LABELED_BLOCK_BODY (exp)) generate_bytecode_insns (LABELED_BLOCK_BODY (exp), target, state); if (state->labeled_blocks != end_label) abort(); state->labeled_blocks = end_label->next; define_jcf_label (end_label, state); } break; case LOOP_EXPR: { tree body = TREE_OPERAND (exp, 0);#if 0 if (TREE_CODE (body) == COMPOUND_EXPR && TREE_CODE (TREE_OPERAND (body, 0)) == EXIT_EXPR) { /* Optimize: H: if (TEST) GOTO L; BODY; GOTO H; L: to: GOTO L; BODY; L: if (!TEST) GOTO L; */ struct jcf_block *head_label; struct jcf_block *body_label; struct jcf_block *end_label = gen_jcf_label (state); struct jcf_block *exit_label = state->labeled_blocks; head_label = gen_jcf_label (state); emit_goto (head_label, state); body_label = get_jcf_label_here (state); generate_bytecode_insns (TREE_OPERAND (body, 1), target, state); define_jcf_label (head_label, state); generate_bytecode_conditional (TREE_OPERAND (body, 0), end_label, body_label, 1, state); define_jcf_label (end_label, state); } else#endif { struct jcf_block *head_label = get_jcf_label_here (state); generate_bytecode_insns (body, IGNORE_TARGET, state); emit_goto (head_label, state); } } break; case EXIT_EXPR: { struct jcf_block *label = state->labeled_blocks; struct jcf_block *end_label = gen_jcf_label (state); generate_bytecode_conditional (TREE_OPERAND (exp, 0), label, end_label, 0, state); define_jcf_label (end_label, state); } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -