📄 codeattr.java
字号:
emitLoad(catchVar); emitThrow(); emitCatchEnd(); emitTryCatchEnd(); } public void emitTryStart(boolean has_finally, Type result_type) { if (result_type != null && result_type.isVoid()) result_type = null; Variable[] savedStack = null; if (result_type != null || SP > 0) pushScope(); if (SP > 0) { savedStack = new Variable[SP]; int i = 0; while (SP > 0) { Variable var = addLocal(topType()); emitStore(var); savedStack[i++] = var; } } TryState try_state = new TryState(this); try_state.savedStack = savedStack; if (result_type != null) try_state.saved_result = addLocal(result_type); if (has_finally) try_state.finally_subr = new Label(); } public void emitTryEnd() { if (try_stack.end_label == null) { if (try_stack.saved_result != null && reachableHere()) emitStore(try_stack.saved_result); try_stack.end_label = new Label(); if (reachableHere()) { if (try_stack.finally_subr != null) emitJsr(try_stack.finally_subr); emitGoto(try_stack.end_label); } try_stack.end_try = getLabel(); } } public void emitCatchStart(Variable var) { emitTryEnd(); SP = 0; if (try_stack.try_type != null) emitCatchEnd(); ClassType type = var == null ? null : (ClassType) var.getType(); try_stack.try_type = type; addHandler(try_stack.start_try, try_stack.end_try, type); if (var != null) { pushType(type); emitStore(var); } else pushType(Type.throwable_type); } public void emitCatchEnd() { if (reachableHere()) { if (try_stack.saved_result != null) emitStore(try_stack.saved_result); if (try_stack.finally_subr != null) emitJsr(try_stack.finally_subr); emitGoto(try_stack.end_label); } try_stack.try_type = null; } public void emitFinallyStart() { emitTryEnd(); if (try_stack.try_type != null) emitCatchEnd(); SP = 0; try_stack.end_try = getLabel(); pushScope(); Type except_type = Type.pointer_type; Variable except = addLocal(except_type); emitCatchStart(null); emitStore(except); emitJsr(try_stack.finally_subr); emitLoad(except); emitThrow(); try_stack.finally_subr.define(this); Type ret_addr_type = Type.pointer_type; try_stack.finally_ret_addr = addLocal(ret_addr_type); pushType(ret_addr_type); emitStore(try_stack.finally_ret_addr); } public void emitFinallyEnd() { emitRet(try_stack.finally_ret_addr); setUnreachable(); popScope(); try_stack.finally_subr = null; } public void emitTryCatchEnd() { if (try_stack.finally_subr != null) emitFinallyEnd(); try_stack.end_label.define(this); Variable[] vars = try_stack.savedStack; if (vars != null) { for (int i = vars.length; --i >= 0; ) { Variable v = vars[i]; if (v != null) { emitLoad(v); } } } if (try_stack.saved_result != null) emitLoad(try_stack.saved_result); if (try_stack.saved_result != null || vars != null) popScope(); try_stack = try_stack.previous; } public final TryState getCurrentTry () { return try_stack; } public final boolean isInTry() { // This also return true if we're in a catch clause, but that is // good enough for now. return try_stack != null; } /** Compile a tail-call to position 0 of the current procedure. * @param pop_args if true, copy argument registers (except this) from stack. * @param scope Scope whose start we jump back to. */ public void emitTailCall (boolean pop_args, Scope scope) { if (pop_args) { Method meth = getMethod(); int arg_slots = ((meth.access_flags & Access.STATIC) != 0) ? 0 : 1; for (int i = meth.arg_types.length; --i >= 0; ) arg_slots += meth.arg_types[i].size > 4 ? 2 : 1; for (int i = meth.arg_types.length; --i >= 0; ) { arg_slots -= meth.arg_types[i].size > 4 ? 2 : 1; emitStore(locals.used [arg_slots]); } } emitGoto(scope.start); } public void processFixups () { if (fixup_count == 0) return; // For each label, set it to its maximum limit, assuming all // fixups causes the code the be expanded. We need a prepass // for this, since FIXUP_MOVEs can cause code to be reordered. // Also, convert each FIXUP_MOVE_TO_END to FIXUP_MOVE. int delta = 0; int instruction_tail = fixup_count; fixupAdd(CodeAttr.FIXUP_MOVE, 0, null); loop1: for (int i = 0; ; ) { int offset = fixup_offsets[i]; int kind = offset & 15; offset >>= 4; Label label = fixup_labels[i]; switch (kind) { case FIXUP_TRY: case FIXUP_LINE_PC: i++; case FIXUP_NONE: case FIXUP_CASE: case FIXUP_DELETE3: break; case FIXUP_DEFINE: label.position += delta; break; case FIXUP_SWITCH: delta += 3; // May need to add up to 3 padding bytes. break; case FIXUP_GOTO: // The first test fails in this case: GOTO L2; L1: L2: FIXME if (label.first_fixup == i + 1 && fixupOffset(i+1) == offset + 3) { // Optimize: GOTO L; L: fixup_offsets[i] = (offset << 4) | FIXUP_DELETE3; fixup_labels[i] = null; delta -= 3; break; } // ... else fall through ... case FIXUP_JSR: if (PC >= 0x8000) delta += 2; // May need to convert goto->goto_w, jsr->jsr_w. break; case FIXUP_TRANSFER: if (PC >= 0x8000) delta += 5; // May need to add a goto_w. break; case FIXUP_MOVE_TO_END: fixup_labels[instruction_tail] = fixup_labels[i+1]; instruction_tail = offset; // ... fall through ... case FIXUP_MOVE: int cur_pc = ((i+1) >= fixup_count ? PC : fixupOffset(fixup_labels[i+1].first_fixup)); fixup_offsets[i] = (cur_pc << 4) | FIXUP_MOVE; if (label == null) break loop1; else { i = label.first_fixup; int next_pc = fixupOffset(i); delta = (cur_pc + delta) - next_pc; continue; } default: throw new Error("unexpected fixup"); } i++; } // Next a loop to fix the position of each label, and calculate // the exact number of code bytes. // Number of bytes to be inserted or (if negative) removed, so far. int new_size = PC; // Current delta between final PC and offset in generate code array. delta = 0; loop2: for (int i = 0; i < fixup_count; ) { int offset = fixup_offsets[i]; int kind = offset & 15; Label label = fixup_labels[i]; if (label != null && label.position < 0) throw new Error ("undefined label "+label); while (label != null && kind >= FIXUP_GOTO && kind <= FIXUP_TRANSFER2 && label.first_fixup + 1 < fixup_count && (fixup_offsets[label.first_fixup + 1] == ((fixup_offsets[label.first_fixup] & 15) | FIXUP_GOTO))) { // Optimize JUMP L; ... L: GOTO X // (where the JUMP is any GOTO or other transfer) // by changing the JUMP L to JUMP X. label = fixup_labels[label.first_fixup + 1]; fixup_labels[i] = label; } offset = offset >> 4; switch (kind) { case FIXUP_TRY: case FIXUP_LINE_PC: i++; case FIXUP_NONE: case FIXUP_CASE: break; case FIXUP_DELETE3: delta -= 3; new_size -= 3; break; case FIXUP_DEFINE: label.position = offset + delta; break; case FIXUP_SWITCH: int padding = 3 - (offset+delta) & 3; delta += padding; new_size += padding; break; case FIXUP_GOTO: case FIXUP_JSR: case FIXUP_TRANSFER: int rel = label.position - (offset+delta); if ((short) rel == rel) { fixup_offsets[i] = (offset << 4) | FIXUP_TRANSFER2; } else { delta += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w new_size += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w } break; case FIXUP_MOVE: if (label == null) break loop2; else { i = label.first_fixup; int next_pc = fixupOffset(i); delta = (offset + delta) - next_pc; continue; } default: throw new Error("unexpected fixup"); } i++; } byte[] new_code = new byte[new_size]; int new_pc = 0; int next_fixup_index = 0; int next_fixup_offset = fixupOffset(0); loop3: for (int old_pc = 0; ; ) { if (old_pc < next_fixup_offset) { new_code[new_pc++] = code[old_pc++]; } else { int kind = fixup_offsets[next_fixup_index] & 15; Label label = fixup_labels[next_fixup_index]; switch (kind) { case FIXUP_NONE: case FIXUP_DEFINE: break; case FIXUP_DELETE3: old_pc += 3; break; case FIXUP_TRANSFER2: delta = label.position - new_pc; new_code[new_pc++] = code[old_pc]; new_code[new_pc++] = (byte) (delta >> 8); new_code[new_pc++] = (byte) (delta & 0xFF); old_pc += 3; break; case FIXUP_GOTO: case FIXUP_JSR: case FIXUP_TRANSFER: delta = label.position - new_pc; byte opcode = code[old_pc]; if (kind == FIXUP_TRANSFER) { // convert: IF_xxx L to IF_NOT_xxx Lt; GOTO L; Lt: opcode = invert_opcode(opcode); new_code[new_pc++] = opcode; new_code[new_pc++] = 0; new_code[new_pc++] = 8; // 8 byte offset to Lt. opcode = (byte) 200; // goto_w } else { // Change goto to goto_w; jsr to jsr_w: opcode = (byte) (opcode + (200-167)); } new_code[new_pc++] = opcode; new_code[new_pc++] = (byte) (delta >> 24); new_code[new_pc++] = (byte) (delta >> 16); new_code[new_pc++] = (byte) (delta >> 8); new_code[new_pc++] = (byte) (delta & 0xFF); old_pc += 3; break; case FIXUP_SWITCH: int padding = 3 - new_pc & 3; int switch_start = new_pc; new_code[new_pc++] = code[old_pc++]; while (--padding >= 0) new_code[new_pc++] = 0; while (next_fixup_index < fixup_count && fixupKind(next_fixup_index + 1) == FIXUP_CASE) { next_fixup_index++; int offset = fixupOffset(next_fixup_index); while (old_pc < offset) new_code[new_pc++] = code[old_pc++]; delta = (fixup_labels[next_fixup_index].position - switch_start); new_code[new_pc++] = (byte) (delta >> 24); new_code[new_pc++] = (byte) (delta >> 16); new_code[new_pc++] = (byte) (delta >> 8); new_code[new_pc++] = (byte) (delta & 0xFF); old_pc += 4; } break; case FIXUP_TRY: addHandler(fixup_labels[next_fixup_index].position, fixup_labels[next_fixup_index+1].position, new_pc, fixupOffset(next_fixup_index+1)); next_fixup_index++; break; case FIXUP_LINE_PC: if (lines == null) lines = new LineNumbersAttr(this); next_fixup_index++; lines.put(fixupOffset(next_fixup_index), new_pc); break; case FIXUP_MOVE: if (label == null) break loop3; else { next_fixup_index = label.first_fixup; old_pc = fixupOffset(next_fixup_index); next_fixup_offset = old_pc; if (label.position != new_pc) throw new Error("bad pc"); continue; } default: throw new Error("unexpected fixup"); } next_fixup_index++; next_fixup_offset = fixupOffset(next_fixup_index); } } if (new_size != new_pc) throw new Error("PC confusion new_pc:"+new_pc+" new_size:"+new_size); PC = new_size; code = new_code; fixup_count = 0; fixup_labels = null; fixup_offsets = null; } public void assignConstants (ClassType cl) { super.assignConstants(cl); if (locals != null && locals.container == null && ! locals.isEmpty()) locals.addToFrontOf(this); processFixups(); Attribute.assignConstants(this, cl); } public final int getLength() { return 12 + getCodeLength() + 8 * exception_table_length + Attribute.getLengthAll(this); } public void write (DataOutputStream dstr) throws java.io.IOException { dstr.writeShort (max_stack); dstr.writeShort (max_locals); dstr.writeInt (PC); dstr.write (code, 0, PC); dstr.writeShort (exception_table_length); int count = exception_table_length; for (int i = 0; --count >= 0; i += 4) { dstr.writeShort(exception_table[i]); dstr.writeShort(exception_table[i+1]); dstr.writeShort(exception_table[i+2]); dstr.writeShort(exception_table[i+3]); } Attribute.writeAll(this, dstr); } public void print (ClassTypeWriter dst) { dst.print("Attribute \""); dst.print(getName()); dst.print("
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -