// We need a special instruction size method, since lookupswitches and tableswitches might not be // properly alligned during relocation int Relocator::rc_instr_len(int bci) { Bytecodes::Code bc= code_at(bci); switch (bc) { // In the case of switch instructions, see if we have the original // padding recorded. case Bytecodes::_tableswitch: case Bytecodes::_lookupswitch: case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: { int pad = get_orig_switch_pad(bci, is_opcode_lookupswitch(bc)); if (pad == -1) { return instruction_length_at(bci); } // Otherwise, depends on the switch type. switch (bc) { case Bytecodes::_tableswitch: { int lo = int_at(bci + 1 + pad + 4 * 1); int hi = int_at(bci + 1 + pad + 4 * 2); int n = hi - lo + 1; return 1 + pad + 4*(3 + n); } case Bytecodes::_lookupswitch: case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: { int npairs = int_at(bci + 1 + pad + 4 * 1); return 1 + pad + 4*(2 + 2*npairs); } default: ShouldNotReachHere(); } } } return instruction_length_at(bci); }
int Bytecodes::special_length_at(address bcp) { Code code = code_at(bcp); switch (code) { case _wide: return wide_length_for(cast(*(bcp + 1))); case _tableswitch: { address aligned_bcp = (address)round_to((intptr_t)bcp + 1, jintSize); jlong lo = (jint)Bytes::get_Java_u4(aligned_bcp + 1*jintSize); jlong hi = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize); jlong len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize; // only return len if it can be represented as a positive int; // return -1 otherwise return (len > 0 && len == (int)len) ? len : -1; } case _lookupswitch: // fall through case _fast_binaryswitch: // fall through case _fast_linearswitch: { address aligned_bcp = (address)round_to((intptr_t)bcp + 1, jintSize); jlong npairs = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize); jlong len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize; // only return len if it can be represented as a positive int; // return -1 otherwise return (len > 0 && len == (int)len) ? len : -1; } } return 0; }
int Bytecodes::special_length_at(address bcp, address end) { Code code = code_at(bcp); switch (code) { case _wide: if (end != NULL && bcp + 1 >= end) { return -1; // don't read past end of code buffer } return wide_length_for(cast(*(bcp + 1))); case _tableswitch: { address aligned_bcp = (address)round_to((intptr_t)bcp + 1, jintSize); if (end != NULL && aligned_bcp + 3*jintSize >= end) { return -1; // don't read past end of code buffer } jlong lo = (jint)Bytes::get_Java_u4(aligned_bcp + 1*jintSize); jlong hi = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize); jlong len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize; // only return len if it can be represented as a positive int; // return -1 otherwise return (len > 0 && len == (int)len) ? len : -1; } case _lookupswitch: // fall through case _fast_binaryswitch: // fall through case _fast_linearswitch: { address aligned_bcp = (address)round_to((intptr_t)bcp + 1, jintSize); if (end != NULL && aligned_bcp + 2*jintSize >= end) { return -1; // don't read past end of code buffer } jlong npairs = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize); jlong len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize; // only return len if it can be represented as a positive int; // return -1 otherwise return (len > 0 && len == (int)len) ? len : -1; } } // Note: Length functions must return <=0 for invalid bytecodes. return 0; }
static int length_at (address bcp) { int l = length_for(code_at(bcp)); return l > 0 ? l : special_length_at(bcp); }
static Code java_code_at(address bcp, methodOop method = NULL) { return java_code(code_at(bcp, method)); }
// handle jump_widen instruction. Called be ChangeJumpWiden class bool Relocator::handle_jump_widen(int bci, int delta) { int ilen = rc_instr_len(bci); Bytecodes::Code bc = code_at(bci); switch (bc) { case Bytecodes::_ifeq: case Bytecodes::_ifne: case Bytecodes::_iflt: case Bytecodes::_ifge: case Bytecodes::_ifgt: case Bytecodes::_ifle: case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne: case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpge: case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: case Bytecodes::_ifnull: case Bytecodes::_ifnonnull: { const int goto_length = Bytecodes::length_for(Bytecodes::_goto); // If 'if' points to the next bytecode after goto, it's already handled. // it shouldn't be. assert (short_at(bci+1) != ilen+goto_length, "if relocation already handled"); assert(ilen == 3, "check length"); // Convert to 0 if <cond> goto 6 // 3 _goto 11 // 6 _goto_w <wide delta offset> // 11 <else code> const int goto_w_length = Bytecodes::length_for(Bytecodes::_goto_w); const int add_bci = goto_length + goto_w_length; if (!relocate_code(bci, 3, /*delta*/add_bci)) return false; // if bytecode points to goto_w instruction short_at_put(bci + 1, ilen + goto_length); int cbci = bci + ilen; // goto around code_at_put(cbci, Bytecodes::_goto); short_at_put(cbci + 1, add_bci); // goto_w <wide delta> cbci = cbci + goto_length; code_at_put(cbci, Bytecodes::_goto_w); if (delta > 0) { delta += 2; // goto_w is 2 bytes more than "if" code } else { delta -= ilen+goto_length; // branch starts at goto_w offset } int_at_put(cbci + 1, delta); break; } case Bytecodes::_goto: case Bytecodes::_jsr: assert(ilen == 3, "check length"); if (!relocate_code(bci, 3, 2)) return false; if (bc == Bytecodes::_goto) code_at_put(bci, Bytecodes::_goto_w); else code_at_put(bci, Bytecodes::_jsr_w); // If it's a forward jump, add 2 for the widening. if (delta > 0) delta += 2; int_at_put(bci + 1, delta); break; default: ShouldNotReachHere(); } return true; }
// Changes all jumps crossing "break_bci" by "delta". May enqueue things // on "rc->changes" void Relocator::change_jumps(int break_bci, int delta) { int bci = 0; Bytecodes::Code bc; // Now, adjust any affected instructions. while (bci < code_length()) { switch (bc= code_at(bci)) { case Bytecodes::_ifeq: case Bytecodes::_ifne: case Bytecodes::_iflt: case Bytecodes::_ifge: case Bytecodes::_ifgt: case Bytecodes::_ifle: case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne: case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpge: case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple: case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne: case Bytecodes::_ifnull: case Bytecodes::_ifnonnull: case Bytecodes::_goto: case Bytecodes::_jsr: change_jump(bci, bci+1, true, break_bci, delta); break; case Bytecodes::_goto_w: case Bytecodes::_jsr_w: change_jump(bci, bci+1, false, break_bci, delta); break; case Bytecodes::_tableswitch: case Bytecodes::_lookupswitch: case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: { int recPad = get_orig_switch_pad(bci, (bc != Bytecodes::_tableswitch)); int oldPad = (recPad != -1) ? recPad : align(bci+1) - (bci+1); if (bci > break_bci) { int new_bci = bci + delta; int newPad = align(new_bci+1) - (new_bci+1); // Do we need to check the padding? if (newPad != oldPad) { if (recPad == -1) { _changes->push(new ChangeSwitchPad(bci, oldPad, (bc != Bytecodes::_tableswitch))); } } } // Then the rest, which depend on the kind of switch. switch (bc) { case Bytecodes::_tableswitch: { change_jump(bci, bci +1 + oldPad, false, break_bci, delta); // We cannot use the Bytecode_tableswitch abstraction, since the padding might not be correct. int lo = int_at(bci + 1 + oldPad + 4 * 1); int hi = int_at(bci + 1 + oldPad + 4 * 2); int n = hi - lo + 1; for (int k = 0; k < n; k++) { change_jump(bci, bci +1 + oldPad + 4*(k+3), false, break_bci, delta); } // Special next-bci calculation here... bci += 1 + oldPad + (n+3)*4; continue; } case Bytecodes::_lookupswitch: case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: { change_jump(bci, bci +1 + oldPad, false, break_bci, delta); // We cannot use the Bytecode_lookupswitch abstraction, since the padding might not be correct. int npairs = int_at(bci + 1 + oldPad + 4 * 1); for (int k = 0; k < npairs; k++) { change_jump(bci, bci + 1 + oldPad + 4*(2 + 2*k + 1), false, break_bci, delta); } /* Special next-bci calculation here... */ bci += 1 + oldPad + (2 + (npairs*2))*4; continue; } default: ShouldNotReachHere(); } } default: break; } bci += rc_instr_len(bci); } }
Bytecodes::Code Bytecodes::code_at(Method* method, int bci) { return code_at(method, method->bcp_from(bci)); }
Bytecodes::Code Bytecodes::code_at(methodOop method, int bci) { return code_at(method->bcp_from(bci), method); }