📄 jcf-write.c
字号:
case EXIT_BLOCK_EXPR: { struct jcf_block *label = state->labeled_blocks; if (TREE_OPERAND (exp, 1) != NULL) goto notimpl; while (label->u.labeled_block != TREE_OPERAND (exp, 0)) label = label->next; call_cleanups (label, state); emit_goto (label, state); } break; case PREDECREMENT_EXPR: value = -1; post_op = 0; goto increment; case PREINCREMENT_EXPR: value = 1; post_op = 0; goto increment; case POSTDECREMENT_EXPR: value = -1; post_op = 1; goto increment; case POSTINCREMENT_EXPR: value = 1; post_op = 1; goto increment; increment: exp = TREE_OPERAND (exp, 0); type = TREE_TYPE (exp); size = TYPE_IS_WIDE (type) ? 2 : 1; if ((TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) && ! TREE_STATIC (exp) && TREE_CODE (type) == INTEGER_TYPE && TYPE_PRECISION (type) == 32) { if (target != IGNORE_TARGET && post_op) emit_load (exp, state); emit_iinc (exp, value, state); if (target != IGNORE_TARGET && ! post_op) emit_load (exp, state); break; } if (TREE_CODE (exp) == COMPONENT_REF) { generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state); emit_dup (1, 0, state); /* Stack: ..., objectref, objectref. */ field_op (TREE_OPERAND (exp, 1), OPCODE_getfield, state); NOTE_PUSH (size-1); /* Stack: ..., objectref, oldvalue. */ offset = 1; } else if (TREE_CODE (exp) == ARRAY_REF) { generate_bytecode_insns (TREE_OPERAND (exp, 0), STACK_TARGET, state); generate_bytecode_insns (TREE_OPERAND (exp, 1), STACK_TARGET, state); emit_dup (2, 0, state); /* Stack: ..., array, index, array, index. */ jopcode = OPCODE_iaload + adjust_typed_op (TREE_TYPE (exp), 7); RESERVE(1); OP1 (jopcode); NOTE_POP (2-size); /* Stack: ..., array, index, oldvalue. */ offset = 2; } else if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) { generate_bytecode_insns (exp, STACK_TARGET, state); /* Stack: ..., oldvalue. */ offset = 0; } else abort (); if (target != IGNORE_TARGET && post_op) emit_dup (size, offset, state); /* Stack, if ARRAY_REF: ..., [result, ] array, index, oldvalue. */ /* Stack, if COMPONENT_REF: ..., [result, ] objectref, oldvalue. */ /* Stack, otherwise: ..., [result, ] oldvalue. */ if (size == 1) push_int_const (value, state); else push_long_const (value, value >= 0 ? 0 : -1, state); NOTE_PUSH (size); emit_binop (OPCODE_iadd + adjust_typed_op (type, 3), type, state); if (target != IGNORE_TARGET && ! post_op) emit_dup (size, offset, state); /* Stack, if ARRAY_REF: ..., [result, ] array, index, newvalue. */ /* Stack, if COMPONENT_REF: ..., [result, ] objectref, newvalue. */ /* Stack, otherwise: ..., [result, ] newvalue. */ goto finish_assignment; case MODIFY_EXPR: { tree lhs = TREE_OPERAND (exp, 0); tree rhs = TREE_OPERAND (exp, 1); int offset = 0; /* See if we can use the iinc instruction. */ if ((TREE_CODE (lhs) == VAR_DECL || TREE_CODE (lhs) == PARM_DECL) && ! TREE_STATIC (lhs) && TREE_CODE (TREE_TYPE (lhs)) == INTEGER_TYPE && TYPE_PRECISION (TREE_TYPE (lhs)) == 32 && (TREE_CODE (rhs) == PLUS_EXPR || TREE_CODE (rhs) == MINUS_EXPR)) { tree arg0 = TREE_OPERAND (rhs, 0); tree arg1 = TREE_OPERAND (rhs, 1); HOST_WIDE_INT min_value = -32768; HOST_WIDE_INT max_value = 32767; if (TREE_CODE (rhs) == MINUS_EXPR) { min_value++; max_value++; } else if (arg1 == lhs) { arg0 = arg1; arg1 = TREE_OPERAND (rhs, 0); } if (lhs == arg0 && TREE_CODE (arg1) == INTEGER_CST) { HOST_WIDE_INT hi_value = TREE_INT_CST_HIGH (arg1); value = TREE_INT_CST_LOW (arg1); if ((hi_value == 0 && value <= max_value) || (hi_value == -1 && value >= min_value)) { if (TREE_CODE (rhs) == MINUS_EXPR) value = -value; emit_iinc (lhs, value, state); break; } } } if (TREE_CODE (lhs) == COMPONENT_REF) { generate_bytecode_insns (TREE_OPERAND (lhs, 0), STACK_TARGET, state); offset = 1; } else if (TREE_CODE (lhs) == ARRAY_REF) { generate_bytecode_insns (TREE_OPERAND(lhs, 0), STACK_TARGET, state); generate_bytecode_insns (TREE_OPERAND(lhs, 1), STACK_TARGET, state); offset = 2; } else offset = 0; generate_bytecode_insns (rhs, STACK_TARGET, state); if (target != IGNORE_TARGET) emit_dup (TYPE_IS_WIDE (type) ? 2 : 1 , offset, state); exp = lhs; } /* FALLTHOUGH */ finish_assignment: if (TREE_CODE (exp) == COMPONENT_REF) { tree field = TREE_OPERAND (exp, 1); if (! FIELD_STATIC (field)) NOTE_POP (1); field_op (field, FIELD_STATIC (field) ? OPCODE_putstatic : OPCODE_putfield, state); NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (field)) ? 2 : 1); } else if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL) { if (FIELD_STATIC (exp)) { field_op (exp, OPCODE_putstatic, state); NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 2 : 1); } else emit_store (exp, state); } else if (TREE_CODE (exp) == ARRAY_REF) { jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (exp), 7); RESERVE(1); OP1 (jopcode); NOTE_POP (TYPE_IS_WIDE (TREE_TYPE (exp)) ? 4 : 3); } else fatal ("internal error (bad lhs to MODIFY_EXPR)"); break; case PLUS_EXPR: jopcode = OPCODE_iadd; goto binop; case MINUS_EXPR: jopcode = OPCODE_isub; goto binop; case MULT_EXPR: jopcode = OPCODE_imul; goto binop; case TRUNC_DIV_EXPR: case RDIV_EXPR: jopcode = OPCODE_idiv; goto binop; case TRUNC_MOD_EXPR: jopcode = OPCODE_irem; goto binop; case LSHIFT_EXPR: jopcode = OPCODE_ishl; goto binop; case RSHIFT_EXPR: jopcode = OPCODE_ishr; goto binop; case URSHIFT_EXPR: jopcode = OPCODE_iushr; goto binop; case TRUTH_AND_EXPR: case BIT_AND_EXPR: jopcode = OPCODE_iand; goto binop; case TRUTH_OR_EXPR: case BIT_IOR_EXPR: jopcode = OPCODE_ior; goto binop; case TRUTH_XOR_EXPR: case BIT_XOR_EXPR: jopcode = OPCODE_ixor; goto binop; binop: { tree arg0 = TREE_OPERAND (exp, 0); tree arg1 = TREE_OPERAND (exp, 1); jopcode += adjust_typed_op (type, 3); if (arg0 == arg1 && TREE_CODE (arg0) == SAVE_EXPR) { /* fold may (e.g) convert 2*x to x+x. */ generate_bytecode_insns (TREE_OPERAND (arg0, 0), target, state); emit_dup (TYPE_PRECISION (TREE_TYPE (arg0)) > 32 ? 2 : 1, 0, state); } else { generate_bytecode_insns (arg0, target, state); generate_bytecode_insns (arg1, target, state); } /* For most binary operations, both operands and the result have the same type. Shift operations are different. Using arg1's type gets us the correct SP adjustment in all casesd. */ if (target == STACK_TARGET) emit_binop (jopcode, TREE_TYPE (arg1), state); break; } case TRUTH_NOT_EXPR: case BIT_NOT_EXPR: generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); if (target == STACK_TARGET) { int is_long = TYPE_PRECISION (TREE_TYPE (exp)) > 32; push_int_const (TREE_CODE (exp) == BIT_NOT_EXPR ? -1 : 1, state); RESERVE (2); if (is_long) OP1 (OPCODE_i2l); NOTE_PUSH (1 + is_long); OP1 (OPCODE_ixor + is_long); NOTE_POP (1 + is_long); } break; case NEGATE_EXPR: jopcode = OPCODE_ineg; jopcode += adjust_typed_op (type, 3); generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); if (target == STACK_TARGET) emit_unop (jopcode, type, state); break; case INSTANCEOF_EXPR: { int index = find_class_constant (&state->cpool, TREE_OPERAND (exp, 1)); generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); RESERVE (3); OP1 (OPCODE_instanceof); OP2 (index); } break; case CONVERT_EXPR: case NOP_EXPR: case FLOAT_EXPR: case FIX_TRUNC_EXPR: { tree src = TREE_OPERAND (exp, 0); tree src_type = TREE_TYPE (src); tree dst_type = TREE_TYPE (exp); generate_bytecode_insns (TREE_OPERAND (exp, 0), target, state); if (target == IGNORE_TARGET || src_type == dst_type) break; if (TREE_CODE (dst_type) == POINTER_TYPE) { if (TREE_CODE (exp) == CONVERT_EXPR) { int index = find_class_constant (&state->cpool, TREE_TYPE (dst_type)); RESERVE (3); OP1 (OPCODE_checkcast); OP2 (index); } } else /* Convert numeric types. */ { int wide_src = TYPE_PRECISION (src_type) > 32; int wide_dst = TYPE_PRECISION (dst_type) > 32; NOTE_POP (1 + wide_src); RESERVE (1); if (TREE_CODE (dst_type) == REAL_TYPE) { if (TREE_CODE (src_type) == REAL_TYPE) OP1 (wide_dst ? OPCODE_f2d : OPCODE_d2f); else if (TYPE_PRECISION (src_type) == 64) OP1 (OPCODE_l2f + wide_dst); else OP1 (OPCODE_i2f + wide_dst); } else /* Convert to integral type. */ { if (TREE_CODE (src_type) == REAL_TYPE) OP1 (OPCODE_f2i + wide_dst + 3 * wide_src); else if (wide_dst) OP1 (OPCODE_i2l); else if (wide_src) OP1 (OPCODE_l2i); if (TYPE_PRECISION (dst_type) < 32) { RESERVE (1); /* Already converted to int, if needed. */ if (TYPE_PRECISION (dst_type) <= 8) OP1 (OPCODE_i2b); else if (TREE_UNSIGNED (dst_type)) OP1 (OPCODE_i2c); else OP1 (OPCODE_i2s); } } NOTE_PUSH (1 + wide_dst); } } break; case CLEANUP_POINT_EXPR: { struct jcf_block *save_labeled_blocks = state->labeled_blocks; int can_complete = CAN_COMPLETE_NORMALLY (TREE_OPERAND (exp, 0)); generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state); if (target != IGNORE_TARGET) abort (); while (state->labeled_blocks != save_labeled_blocks) { struct jcf_block *finished_label = NULL; tree return_link; tree exception_type = build_pointer_type (throwable_type_node); tree exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type); struct jcf_block *end_label = get_jcf_label_here (state); struct jcf_block *label = state->labeled_blocks; struct jcf_handler *handler; tree cleanup = label->u.labeled_block; state->labeled_blocks = label->next; state->num_finalizers--; if (can_complete) { finished_label = gen_jcf_label (state); emit_jsr (label, state); emit_goto (finished_label, state); if (! CAN_COMPLETE_NORMALLY (cleanup)) can_complete = 0; } handler = alloc_handler (label->v.start_label, end_label, state); handler->type = NULL_TREE; localvar_alloc (exception_decl, state); NOTE_PUSH (1); emit_store (exception_decl, state); emit_jsr (label, state); emit_load (exception_decl, state); RESERVE (1); OP1 (OPCODE_athrow); NOTE_POP (1); /* The finally block. */ return_link = build_decl (VAR_DECL, NULL_TREE, return_address_type_node); define_jcf_label (label, state); NOTE_PUSH (1); localvar_alloc (return_link, state); emit_store (return_link, state); generate_bytecode_insns (cleanup, IGNORE_TARGET, state); maybe_wide (OPCODE_ret, DECL_LOCAL_INDEX (return_link), state); localvar_free (return_link, state); localvar_free (exception_decl, state); if (finished_label != NULL) define_jcf_label (finished_label, state); } } break; case WITH_CLEANUP_EXPR: { struct jcf_block *label; generate_bytecode_insns (TREE_OPERAND (exp, 0), IGNORE_TARGET, state); label = gen_jcf_label (state); label->pc = PENDING_CLEANUP_PC; label->next = state->labeled_blocks; state->labeled_blocks = label; state->num_finalizers++; label->u.labeled_block = TREE_OPERAND (exp, 2); label->v.start_label = get_jcf_label_here (state); if (target != IGNORE_TARGET) abort (); } break; case TRY_EXPR: { tree try_clause = TREE_OPERAND (exp, 0); struct jcf_block *start_label = get_jcf_label_here (state); struct jcf_block *end_label; /* End of try clause. */ struct jcf_block *finished_label = gen_jcf_label (state); tree clause = TREE_OPERAND (exp, 1); if (target != IGNORE_TARGET) abort (); generate_bytecode_insns (try_clause, IGNORE_TARGET, state); end_label = get_jcf_label_here (state); if (CAN_COMPLETE_NORMALLY (try_clause)) emit_goto (finished_label, state); while (clause != NULL_TREE) { tree catch_clause = TREE_OPERAND (clause, 0); tree exception_decl = BLOCK_EXPR_DECLS (catch_clause); struct jcf_handler *handler = alloc_handler (start_label, end_label, state); if (exception_decl == NULL_TREE) handler->type = NULL_TREE; else handler->type = TREE_TYPE (TREE_TYPE (exception_decl)); generate_bytecode_insns (catch_clause, IGNORE_TARGET, state); clause = TREE_CHAIN (clause); if (CAN_COMPLETE_NORMALLY (catch_clause) && clause != NULL_TREE) emit_goto (finished_label, state); } define_jcf_label (finished_label, state); } break; case TRY_FINALLY_EXPR: { tree try_block = TREE_OPERAND (exp, 0); tree finally = TREE_OPERAND (exp, 1); struct jcf_block *finished_label = gen_jcf_label (state); struct jcf_block *finally_label = gen_jcf_label (state); struct jcf_block *start_label = get_jcf_label_here (state); tree return_link = build_decl (VAR_DECL, NULL_TREE, return_address_type_node); tree exception_type = build_pointer_type (throwable_type_node); tree exception_decl = build_decl (VAR_DECL, NULL_TREE, exception_type); struct jcf_handler *handler; finally_label->pc = PENDING_CLEANUP_PC; finally_label->next = state->labeled_blocks; state->labeled_blocks = finally_label; state->num_finalizers++; generate_bytecode_insns (try_block, target, state); if (state->labeled_blocks != finally_label) abort(); state->labeled_blocks = finally_label->next; emit_jsr (finally_label, state); if (CAN_COMPLETE_NORMALLY (try_block)) emit_goto (finished_label, state); /* Handle exceptions. */ localvar_alloc (return_link, state); handler = alloc_handler (start_label, NULL_TREE, state); handler->end_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -