📄 jcf-write.c
字号:
int value; struct jcf_partial *state;{ int slot = DECL_LOCAL_INDEX (var); if (value < -128 || value > 127 || slot >= 256) { RESERVE (6); OP1 (OPCODE_wide); OP1 (OPCODE_iinc); OP2 (slot); OP2 (value); } else { RESERVE (3); OP1 (OPCODE_iinc); OP1 (slot); OP1 (value); }}static voidemit_load_or_store (var, opcode, state) tree var; /* Variable to load from or store into. */ int opcode; /* Either OPCODE_iload or OPCODE_istore. */ struct jcf_partial *state;{ tree type = TREE_TYPE (var); int kind = adjust_typed_op (type, 4); int index = DECL_LOCAL_INDEX (var); if (index <= 3) { RESERVE (1); OP1 (opcode + 5 + 4 * kind + index); /* [ilfda]{load,store}_[0123] */ } else maybe_wide (opcode + kind, index, state); /* [ilfda]{load,store} */}static voidemit_load (var, state) tree var; struct jcf_partial *state;{ emit_load_or_store (var, OPCODE_iload, state); NOTE_PUSH (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1);}static voidemit_store (var, state) tree var; struct jcf_partial *state;{ emit_load_or_store (var, OPCODE_istore, state); NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (var)) ? 2 : 1);}static voidemit_unop (opcode, type, state) enum java_opcode opcode; tree type ATTRIBUTE_UNUSED; struct jcf_partial *state;{ RESERVE(1); OP1 (opcode);}static voidemit_binop (opcode, type, state) enum java_opcode opcode; tree type; struct jcf_partial *state;{ int size = TYPE_IS_WIDE (type) ? 2 : 1; RESERVE(1); OP1 (opcode); NOTE_POP (size);}static voidemit_reloc (value, kind, target, state) HOST_WIDE_INT value; int kind; struct jcf_block *target; struct jcf_partial *state;{ struct jcf_relocation *reloc = (struct jcf_relocation *) obstack_alloc (state->chunk_obstack, sizeof (struct jcf_relocation)); struct jcf_block *block = state->last_block; reloc->next = block->u.relocations; block->u.relocations = reloc; reloc->offset = BUFFER_LENGTH (&state->bytecode); reloc->label = target; reloc->kind = kind; if (kind == 0 || kind == BLOCK_START_RELOC) OP4 (value); else if (kind != SWITCH_ALIGN_RELOC) OP2 (value);}static voidemit_switch_reloc (label, state) struct jcf_block *label; struct jcf_partial *state;{ emit_reloc (0, BLOCK_START_RELOC, label, state);}/* Similar to emit_switch_reloc, but re-uses an existing case reloc. */static voidemit_case_reloc (reloc, state) struct jcf_relocation *reloc; struct jcf_partial *state;{ struct jcf_block *block = state->last_block; reloc->next = block->u.relocations; block->u.relocations = reloc; reloc->offset = BUFFER_LENGTH (&state->bytecode); reloc->kind = BLOCK_START_RELOC; OP4 (0);}/* Emit a conditional jump to TARGET with a 2-byte relative jump offset The opcode is OPCODE, the inverted opcode is INV_OPCODE. */static voidemit_if (target, opcode, inv_opcode, state) struct jcf_block *target; int opcode, inv_opcode; struct jcf_partial *state;{ OP1 (opcode); // value is 1 byte from reloc back to start of instruction. emit_reloc (1, - inv_opcode, target, state);}static voidemit_goto (target, state) struct jcf_block *target; struct jcf_partial *state;{ OP1 (OPCODE_goto); // Value is 1 byte from reloc back to start of instruction. emit_reloc (1, OPCODE_goto_w, target, state);}static voidemit_jsr (target, state) struct jcf_block *target; struct jcf_partial *state;{ OP1 (OPCODE_jsr); // Value is 1 byte from reloc back to start of instruction. emit_reloc (1, OPCODE_jsr_w, target, state);}/* Generate code to evaluate EXP. If the result is true, branch to TRUE_LABEL; otherwise, branch to FALSE_LABEL. TRUE_BRANCH_FIRST is a code geneation hint that the TRUE_LABEL may follow right after this. (The idea is that we may be able to optimize away GOTO TRUE_LABEL; TRUE_LABEL:) */static voidgenerate_bytecode_conditional (exp, true_label, false_label, true_branch_first, state) tree exp; struct jcf_block *true_label; struct jcf_block *false_label; int true_branch_first; struct jcf_partial *state;{ tree exp0, exp1, type; int save_SP = state->code_SP; enum java_opcode op, negop; switch (TREE_CODE (exp)) { case INTEGER_CST: emit_goto (integer_zerop (exp) ? false_label : true_label, state); break; case COND_EXPR: { struct jcf_block *then_label = gen_jcf_label (state); struct jcf_block *else_label = gen_jcf_label (state); int save_SP_before, save_SP_after; generate_bytecode_conditional (TREE_OPERAND (exp, 0), then_label, else_label, 1, state); define_jcf_label (then_label, state); save_SP_before = state->code_SP; generate_bytecode_conditional (TREE_OPERAND (exp, 1), true_label, false_label, 1, state); save_SP_after = state->code_SP; state->code_SP = save_SP_before; define_jcf_label (else_label, state); generate_bytecode_conditional (TREE_OPERAND (exp, 2), true_label, false_label, true_branch_first, state); if (state->code_SP != save_SP_after) fatal ("internal error non-matching SP"); } break; case TRUTH_NOT_EXPR: generate_bytecode_conditional (TREE_OPERAND (exp, 0), false_label, true_label, ! true_branch_first, state); break; case TRUTH_ANDIF_EXPR: { struct jcf_block *next_label = gen_jcf_label (state); generate_bytecode_conditional (TREE_OPERAND (exp, 0), next_label, false_label, 1, state); define_jcf_label (next_label, state); generate_bytecode_conditional (TREE_OPERAND (exp, 1), true_label, false_label, 1, state); } break; case TRUTH_ORIF_EXPR: { struct jcf_block *next_label = gen_jcf_label (state); generate_bytecode_conditional (TREE_OPERAND (exp, 0), true_label, next_label, 1, state); define_jcf_label (next_label, state); generate_bytecode_conditional (TREE_OPERAND (exp, 1), true_label, false_label, 1, state); } break; compare_1: /* Assuming op is one of the 2-operand if_icmp<COND> instructions, set it to the corresponding 1-operand if<COND> instructions. */ op = op - 6; /* FALLTHROUGH */ compare_2: /* The opcodes with their inverses are allocated in pairs. E.g. The inverse of if_icmplt (161) is if_icmpge (162). */ negop = (op & 1) ? op + 1 : op - 1; compare_2_ptr: if (true_branch_first) { emit_if (false_label, negop, op, state); emit_goto (true_label, state); } else { emit_if (true_label, op, negop, state); emit_goto (false_label, state); } break; case EQ_EXPR: op = OPCODE_if_icmpeq; goto compare; case NE_EXPR: op = OPCODE_if_icmpne; goto compare; case GT_EXPR: op = OPCODE_if_icmpgt; goto compare; case LT_EXPR: op = OPCODE_if_icmplt; goto compare; case GE_EXPR: op = OPCODE_if_icmpge; goto compare; case LE_EXPR: op = OPCODE_if_icmple; goto compare; compare: exp0 = TREE_OPERAND (exp, 0); exp1 = TREE_OPERAND (exp, 1); type = TREE_TYPE (exp0); switch (TREE_CODE (type)) { int opf; case POINTER_TYPE: case RECORD_TYPE: switch (TREE_CODE (exp)) { case EQ_EXPR: op = OPCODE_if_acmpeq; break; case NE_EXPR: op = OPCODE_if_acmpne; break; default: abort(); } if (integer_zerop (exp1) || integer_zerop (exp0)) { generate_bytecode_insns (integer_zerop (exp1) ? exp0 : exp0, STACK_TARGET, state); op = op + (OPCODE_ifnull - OPCODE_if_acmpeq); negop = (op & 1) ? op - 1 : op + 1; NOTE_POP (1); goto compare_2_ptr; } generate_bytecode_insns (exp0, STACK_TARGET, state); generate_bytecode_insns (exp1, STACK_TARGET, state); NOTE_POP (2); goto compare_2; case REAL_TYPE: generate_bytecode_insns (exp0, STACK_TARGET, state); generate_bytecode_insns (exp1, STACK_TARGET, state); if (op == OPCODE_if_icmplt || op == OPCODE_if_icmple) opf = OPCODE_fcmpg; else opf = OPCODE_fcmpl; if (TYPE_PRECISION (type) > 32) { opf += 2; NOTE_POP (4); } else NOTE_POP (2); RESERVE (1); OP1 (opf); goto compare_1; case INTEGER_TYPE: if (TYPE_PRECISION (type) > 32) { generate_bytecode_insns (exp0, STACK_TARGET, state); generate_bytecode_insns (exp1, STACK_TARGET, state); NOTE_POP (4); RESERVE (1); OP1 (OPCODE_lcmp); goto compare_1; } /* FALLTHOUGH */ default: if (integer_zerop (exp1)) { generate_bytecode_insns (exp0, STACK_TARGET, state); NOTE_POP (1); goto compare_1; } if (integer_zerop (exp0)) { switch (op) { case OPCODE_if_icmplt: case OPCODE_if_icmpge: op += 2; break; case OPCODE_if_icmpgt: case OPCODE_if_icmple: op -= 2; break; default: break; } generate_bytecode_insns (exp1, STACK_TARGET, state); NOTE_POP (1); goto compare_1; } generate_bytecode_insns (exp0, STACK_TARGET, state); generate_bytecode_insns (exp1, STACK_TARGET, state); NOTE_POP (2); goto compare_2; } default: generate_bytecode_insns (exp, STACK_TARGET, state); NOTE_POP (1); if (true_branch_first) { emit_if (false_label, OPCODE_ifeq, OPCODE_ifne, state); emit_goto (true_label, state); } else { emit_if (true_label, OPCODE_ifne, OPCODE_ifeq, state); emit_goto (false_label, state); } break; } if (save_SP != state->code_SP) fatal ("internal error - SP mismatch");}/* Call pending cleanups i.e. those for surrounding CLEANUP_POINT_EXPRs but only as far out as LIMIT (since we are about to jump to the emit label that is LIMIT). */static voidcall_cleanups (limit, state) struct jcf_block *limit; struct jcf_partial *state;{ struct jcf_block *block = state->labeled_blocks; for (; block != limit; block = block->next) { if (block->pc == PENDING_CLEANUP_PC) emit_jsr (block, state); }}static voidgenerate_bytecode_return (exp, state) tree exp; struct jcf_partial *state;{ tree return_type = TREE_TYPE (TREE_TYPE (state->current_method)); int returns_void = TREE_CODE (return_type) == VOID_TYPE; int op; again: if (exp != NULL) { switch (TREE_CODE (exp)) { case COMPOUND_EXPR: generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state); exp = TREE_OPERAND (exp, 1); goto again; case COND_EXPR: { struct jcf_block *then_label = gen_jcf_label (state); struct jcf_block *else_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_return (TREE_OPERAND (exp, 1), state); define_jcf_label (else_label, state); generate_bytecode_return (TREE_OPERAND (exp, 2), state); } return; default: generate_bytecode_insns (exp, returns_void ? IGNORE_TARGET : STACK_TARGET, state); } } if (returns_void) { op = OPCODE_return; call_cleanups (NULL_TREE, state); } else { op = OPCODE_ireturn + adjust_typed_op (return_type, 4); if (state->num_finalizers > 0) { if (state->return_value_decl == NULL_TREE) { state->return_value_decl = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp)); localvar_alloc (state->return_value_decl, state); } emit_store (state->return_value_decl, state); call_cleanups (NULL_TREE, state); emit_load (state->return_value_decl, state); /* If we call localvar_free (state->return_value_decl, state), then we risk the save decl erroneously re-used in the finalizer. Instead, we keep the state->return_value_decl allocated through the rest of the method. This is not the greatest solution, but it is at least simple and safe. */ } } RESERVE (1); OP1 (op);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -