src/share/vm/runtime/relocator.cpp

changeset 435
a61af66fc99e
child 1907
c18cbe5936b8
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/runtime/relocator.cpp	Sat Dec 01 00:00:00 2007 +0000
     1.3 @@ -0,0 +1,647 @@
     1.4 +/*
     1.5 + * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    1.24 + * have any questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +# include "incls/_precompiled.incl"
    1.29 +# include "incls/_relocator.cpp.incl"
    1.30 +
    1.31 +#define MAX_METHOD_LENGTH  65535
    1.32 +
    1.33 +#define MAX_SHORT ((1 << 15) - 1)
    1.34 +#define MIN_SHORT (- (1 << 15))
    1.35 +
    1.36 +// Encapsulates a code change request. There are 3 types.
    1.37 +// General instruction, jump instruction, and table/lookup switches
    1.38 +//
    1.39 +class ChangeItem : public ResourceObj {
    1.40 +  int _bci;
    1.41 + public:
    1.42 +   ChangeItem(int bci) { _bci = bci; }
    1.43 +   virtual bool handle_code_change(Relocator *r) = 0;
    1.44 +
    1.45 +   // type info
    1.46 +   virtual bool is_widen()      { return false; }
    1.47 +   virtual bool is_jump_widen() { return false; }
    1.48 +   virtual bool is_switch_pad() { return false; }
    1.49 +
    1.50 +   // accessors
    1.51 +   int bci()    { return _bci; }
    1.52 +   void relocate(int break_bci, int delta) { if (_bci > break_bci) { _bci += delta; } }
    1.53 +
    1.54 +   virtual bool adjust(int bci, int delta) { return false; }
    1.55 +
    1.56 +   // debug
    1.57 +   virtual void print() = 0;
    1.58 +};
    1.59 +
    1.60 +class ChangeWiden : public ChangeItem {
    1.61 +  int              _new_ilen;    // New length of instruction at bci
    1.62 +  u_char*          _inst_buffer; // New bytecodes
    1.63 + public:
    1.64 +  ChangeWiden(int bci, int new_ilen, u_char* inst_buffer) : ChangeItem(bci) {
    1.65 +    _new_ilen = new_ilen;
    1.66 +    _inst_buffer = inst_buffer;
    1.67 +  }
    1.68 +
    1.69 +  // Callback to do instruction
    1.70 +  bool handle_code_change(Relocator *r) { return r->handle_widen(bci(), _new_ilen, _inst_buffer); };
    1.71 +
    1.72 +  bool is_widen()              { return true; }
    1.73 +
    1.74 +  void print()                 { tty->print_cr("ChangeWiden. bci: %d   New_ilen: %d", bci(), _new_ilen); }
    1.75 +};
    1.76 +
    1.77 +class ChangeJumpWiden : public ChangeItem {
    1.78 +  int _delta;  // New length of instruction at bci
    1.79 + public:
    1.80 +  ChangeJumpWiden(int bci, int delta) : ChangeItem(bci) { _delta = delta; }
    1.81 +
    1.82 +  // Callback to do instruction
    1.83 +  bool handle_code_change(Relocator *r) { return r->handle_jump_widen(bci(), _delta); };
    1.84 +
    1.85 +  bool is_jump_widen()         { return true; }
    1.86 +
    1.87 +  // If the bci matches, adjust the delta in the change jump request.
    1.88 +  bool adjust(int jump_bci, int delta) {
    1.89 +    if (bci() == jump_bci) {
    1.90 +      if (_delta > 0)
    1.91 +        _delta += delta;
    1.92 +      else
    1.93 +        _delta -= delta;
    1.94 +      return true;
    1.95 +    }
    1.96 +    return false;
    1.97 +  }
    1.98 +
    1.99 +  void print()                 { tty->print_cr("ChangeJumpWiden. bci: %d   Delta: %d", bci(), _delta); }
   1.100 +};
   1.101 +
   1.102 +class ChangeSwitchPad : public ChangeItem {
   1.103 +  int  _padding;
   1.104 +  bool _is_lookup_switch;
   1.105 + public:
   1.106 +   ChangeSwitchPad(int bci, int padding, bool is_lookup_switch) : ChangeItem(bci) {
   1.107 +     _padding = padding;
   1.108 +     _is_lookup_switch = is_lookup_switch;
   1.109 +   }
   1.110 +
   1.111 +   // Callback to do instruction
   1.112 +   bool handle_code_change(Relocator *r) { return r->handle_switch_pad(bci(), _padding, _is_lookup_switch); };
   1.113 +
   1.114 +   bool is_switch_pad()        { return true; }
   1.115 +   int  padding()              { return _padding;  }
   1.116 +   bool is_lookup_switch()     { return _is_lookup_switch; }
   1.117 +
   1.118 +   void print()                { tty->print_cr("ChangeSwitchPad. bci: %d   Padding: %d  IsLookupSwitch: %d", bci(), _padding, _is_lookup_switch); }
   1.119 +};
   1.120 +
   1.121 +//-----------------------------------------------------------------------------------------------------------
   1.122 +// Relocator code
   1.123 +
   1.124 +Relocator::Relocator(methodHandle m, RelocatorListener* listener) {
   1.125 +  set_method(m);
   1.126 +  set_code_length(method()->code_size());
   1.127 +  set_code_array(NULL);
   1.128 +  // Allocate code array and copy bytecodes
   1.129 +  if (!expand_code_array(0)) {
   1.130 +    // Should have at least MAX_METHOD_LENGTH available or the verifier
   1.131 +    // would have failed.
   1.132 +    ShouldNotReachHere();
   1.133 +  }
   1.134 +  set_compressed_line_number_table(NULL);
   1.135 +  set_compressed_line_number_table_size(0);
   1.136 +  _listener = listener;
   1.137 +}
   1.138 +
   1.139 +// size is the new size of the instruction at bci. Hence, if size is less than the current
   1.140 +// instruction sice, we will shrink the code.
   1.141 +methodHandle Relocator::insert_space_at(int bci, int size, u_char inst_buffer[], TRAPS) {
   1.142 +  _changes = new GrowableArray<ChangeItem*> (10);
   1.143 +  _changes->push(new ChangeWiden(bci, size, inst_buffer));
   1.144 +
   1.145 +  if (TraceRelocator) {
   1.146 +    tty->print_cr("Space at: %d Size: %d", bci, size);
   1.147 +    _method->print();
   1.148 +    _method->print_codes();
   1.149 +    tty->print_cr("-------------------------------------------------");
   1.150 +  }
   1.151 +
   1.152 +  if (!handle_code_changes()) return methodHandle();
   1.153 +
   1.154 +    // Construct the new method
   1.155 +  methodHandle new_method = methodOopDesc::clone_with_new_data(method(),
   1.156 +                              code_array(), code_length(),
   1.157 +                              compressed_line_number_table(),
   1.158 +                              compressed_line_number_table_size(),
   1.159 +                              CHECK_(methodHandle()));
   1.160 +    set_method(new_method);
   1.161 +
   1.162 +  if (TraceRelocator) {
   1.163 +    tty->print_cr("-------------------------------------------------");
   1.164 +    tty->print_cr("new method");
   1.165 +    _method->print_codes();
   1.166 +  }
   1.167 +
   1.168 +  return new_method;
   1.169 +}
   1.170 +
   1.171 +
   1.172 +bool Relocator::handle_code_changes() {
   1.173 +  assert(_changes != NULL, "changes vector must be initialized");
   1.174 +
   1.175 +  while (!_changes->is_empty()) {
   1.176 +    // Inv: everything is aligned.
   1.177 +    ChangeItem* ci = _changes->first();
   1.178 +
   1.179 +    if (TraceRelocator) {
   1.180 +      ci->print();
   1.181 +    }
   1.182 +
   1.183 +    // Execute operation
   1.184 +    if (!ci->handle_code_change(this)) return false;
   1.185 +
   1.186 +    // Shuffel items up
   1.187 +    for (int index = 1; index < _changes->length(); index++) {
   1.188 +      _changes->at_put(index-1, _changes->at(index));
   1.189 +    }
   1.190 +    _changes->pop();
   1.191 +  }
   1.192 +  return true;
   1.193 +}
   1.194 +
   1.195 +
   1.196 +bool Relocator::is_opcode_lookupswitch(Bytecodes::Code bc) {
   1.197 +  switch (bc) {
   1.198 +    case Bytecodes::_tableswitch:       return false;
   1.199 +    case Bytecodes::_lookupswitch:                   // not rewritten on ia64
   1.200 +    case Bytecodes::_fast_linearswitch:              // rewritten _lookupswitch
   1.201 +    case Bytecodes::_fast_binaryswitch: return true; // rewritten _lookupswitch
   1.202 +    default: ShouldNotReachHere();
   1.203 +  }
   1.204 +  return true; // dummy
   1.205 +}
   1.206 +
   1.207 +// We need a special instruction size method, since lookupswitches and tableswitches might not be
   1.208 +// properly alligned during relocation
   1.209 +int Relocator::rc_instr_len(int bci) {
   1.210 +  Bytecodes::Code bc= code_at(bci);
   1.211 +  switch (bc) {
   1.212 +    // In the case of switch instructions, see if we have the original
   1.213 +    // padding recorded.
   1.214 +    case Bytecodes::_tableswitch:
   1.215 +    case Bytecodes::_lookupswitch:
   1.216 +    case Bytecodes::_fast_linearswitch:
   1.217 +    case Bytecodes::_fast_binaryswitch:
   1.218 +    {
   1.219 +      int pad = get_orig_switch_pad(bci, is_opcode_lookupswitch(bc));
   1.220 +      if (pad == -1) {
   1.221 +        return instruction_length_at(bci);
   1.222 +      }
   1.223 +      // Otherwise, depends on the switch type.
   1.224 +      switch (bc) {
   1.225 +        case Bytecodes::_tableswitch: {
   1.226 +          int lo = int_at(bci + 1 + pad + 4 * 1);
   1.227 +          int hi = int_at(bci + 1 + pad + 4 * 2);
   1.228 +          int n = hi - lo + 1;
   1.229 +          return 1 + pad + 4*(3 + n);
   1.230 +        }
   1.231 +        case Bytecodes::_lookupswitch:
   1.232 +        case Bytecodes::_fast_linearswitch:
   1.233 +        case Bytecodes::_fast_binaryswitch: {
   1.234 +          int npairs = int_at(bci + 1 + pad + 4 * 1);
   1.235 +          return 1 + pad + 4*(2 + 2*npairs);
   1.236 +        }
   1.237 +        default:
   1.238 +          ShouldNotReachHere();
   1.239 +      }
   1.240 +    }
   1.241 +  }
   1.242 +  return instruction_length_at(bci);
   1.243 +}
   1.244 +
   1.245 +// If a change item is recorded for "pc", with type "ct", returns the
   1.246 +// associated padding, else -1.
   1.247 +int Relocator::get_orig_switch_pad(int bci, bool is_lookup_switch) {
   1.248 +  for (int k = 0; k < _changes->length(); k++) {
   1.249 +    ChangeItem* ci = _changes->at(k);
   1.250 +    if (ci->is_switch_pad()) {
   1.251 +      ChangeSwitchPad* csp = (ChangeSwitchPad*)ci;
   1.252 +      if (csp->is_lookup_switch() == is_lookup_switch && csp->bci() == bci) {
   1.253 +        return csp->padding();
   1.254 +      }
   1.255 +    }
   1.256 +  }
   1.257 +  return -1;
   1.258 +}
   1.259 +
   1.260 +
   1.261 +// Push a ChangeJumpWiden if it doesn't already exist on the work queue,
   1.262 +// otherwise adjust the item already there by delta.  The calculation for
   1.263 +// new_delta is wrong for this because it uses the offset stored in the
   1.264 +// code stream itself which wasn't fixed when item was pushed on the work queue.
   1.265 +void Relocator::push_jump_widen(int bci, int delta, int new_delta) {
   1.266 +  for (int j = 0; j < _changes->length(); j++) {
   1.267 +    ChangeItem* ci = _changes->at(j);
   1.268 +    if (ci->adjust(bci, delta)) return;
   1.269 +  }
   1.270 +  _changes->push(new ChangeJumpWiden(bci, new_delta));
   1.271 +}
   1.272 +
   1.273 +
   1.274 +// The current instruction of "c" is a jump; one of its offset starts
   1.275 +// at "offset" and is a short if "isShort" is "TRUE",
   1.276 +// and an integer otherwise.  If the jump crosses "breakPC", change
   1.277 +// the span of the jump by "delta".
   1.278 +void Relocator::change_jump(int bci, int offset, bool is_short, int break_bci, int delta) {
   1.279 +  int bci_delta = (is_short) ? short_at(offset) : int_at(offset);
   1.280 +  int targ = bci + bci_delta;
   1.281 +
   1.282 +  if ((bci <= break_bci && targ >  break_bci) ||
   1.283 +      (bci >  break_bci && targ <= break_bci)) {
   1.284 +    int new_delta;
   1.285 +    if (bci_delta > 0)
   1.286 +      new_delta = bci_delta + delta;
   1.287 +    else
   1.288 +      new_delta = bci_delta - delta;
   1.289 +
   1.290 +    if (is_short && ((new_delta > MAX_SHORT) || new_delta < MIN_SHORT)) {
   1.291 +      push_jump_widen(bci, delta, new_delta);
   1.292 +    } else if (is_short) {
   1.293 +      short_at_put(offset, new_delta);
   1.294 +    } else {
   1.295 +      int_at_put(offset, new_delta);
   1.296 +    }
   1.297 +  }
   1.298 +}
   1.299 +
   1.300 +
   1.301 +// Changes all jumps crossing "break_bci" by "delta".  May enqueue things
   1.302 +// on "rc->changes"
   1.303 +void Relocator::change_jumps(int break_bci, int delta) {
   1.304 +  int bci = 0;
   1.305 +  Bytecodes::Code bc;
   1.306 +  // Now, adjust any affected instructions.
   1.307 +  while (bci < code_length()) {
   1.308 +    switch (bc= code_at(bci)) {
   1.309 +      case Bytecodes::_ifeq:
   1.310 +      case Bytecodes::_ifne:
   1.311 +      case Bytecodes::_iflt:
   1.312 +      case Bytecodes::_ifge:
   1.313 +      case Bytecodes::_ifgt:
   1.314 +      case Bytecodes::_ifle:
   1.315 +      case Bytecodes::_if_icmpeq:
   1.316 +      case Bytecodes::_if_icmpne:
   1.317 +      case Bytecodes::_if_icmplt:
   1.318 +      case Bytecodes::_if_icmpge:
   1.319 +      case Bytecodes::_if_icmpgt:
   1.320 +      case Bytecodes::_if_icmple:
   1.321 +      case Bytecodes::_if_acmpeq:
   1.322 +      case Bytecodes::_if_acmpne:
   1.323 +      case Bytecodes::_ifnull:
   1.324 +      case Bytecodes::_ifnonnull:
   1.325 +      case Bytecodes::_goto:
   1.326 +      case Bytecodes::_jsr:
   1.327 +        change_jump(bci, bci+1, true, break_bci, delta);
   1.328 +        break;
   1.329 +      case Bytecodes::_goto_w:
   1.330 +      case Bytecodes::_jsr_w:
   1.331 +        change_jump(bci, bci+1, false, break_bci, delta);
   1.332 +        break;
   1.333 +      case Bytecodes::_tableswitch:
   1.334 +      case Bytecodes::_lookupswitch:
   1.335 +      case Bytecodes::_fast_linearswitch:
   1.336 +      case Bytecodes::_fast_binaryswitch: {
   1.337 +        int recPad = get_orig_switch_pad(bci, (bc != Bytecodes::_tableswitch));
   1.338 +        int oldPad = (recPad != -1) ? recPad : align(bci+1) - (bci+1);
   1.339 +        if (bci > break_bci) {
   1.340 +          int new_bci = bci + delta;
   1.341 +          int newPad = align(new_bci+1) - (new_bci+1);
   1.342 +          // Do we need to check the padding?
   1.343 +          if (newPad != oldPad) {
   1.344 +            if (recPad == -1) {
   1.345 +              _changes->push(new ChangeSwitchPad(bci, oldPad, (bc != Bytecodes::_tableswitch)));
   1.346 +            }
   1.347 +          }
   1.348 +        }
   1.349 +
   1.350 +        // Then the rest, which depend on the kind of switch.
   1.351 +        switch (bc) {
   1.352 +          case Bytecodes::_tableswitch: {
   1.353 +            change_jump(bci, bci +1 + oldPad, false, break_bci, delta);
   1.354 +            // We cannot use the Bytecode_tableswitch abstraction, since the padding might not be correct.
   1.355 +            int lo = int_at(bci + 1 + oldPad + 4 * 1);
   1.356 +            int hi = int_at(bci + 1 + oldPad + 4 * 2);
   1.357 +            int n = hi - lo + 1;
   1.358 +            for (int k = 0; k < n; k++) {
   1.359 +              change_jump(bci, bci +1 + oldPad + 4*(k+3), false, break_bci, delta);
   1.360 +            }
   1.361 +            // Special next-bci calculation here...
   1.362 +            bci += 1 + oldPad + (n+3)*4;
   1.363 +            continue;
   1.364 +          }
   1.365 +          case Bytecodes::_lookupswitch:
   1.366 +          case Bytecodes::_fast_linearswitch:
   1.367 +          case Bytecodes::_fast_binaryswitch: {
   1.368 +            change_jump(bci, bci +1 + oldPad, false, break_bci, delta);
   1.369 +            // We cannot use the Bytecode_lookupswitch abstraction, since the padding might not be correct.
   1.370 +            int npairs = int_at(bci + 1 + oldPad + 4 * 1);
   1.371 +            for (int k = 0; k < npairs; k++) {
   1.372 +              change_jump(bci, bci + 1 + oldPad + 4*(2 + 2*k + 1), false, break_bci, delta);
   1.373 +            }
   1.374 +            /* Special next-bci calculation here... */
   1.375 +            bci += 1 + oldPad + (2 + (npairs*2))*4;
   1.376 +            continue;
   1.377 +          }
   1.378 +          default:
   1.379 +            ShouldNotReachHere();
   1.380 +        }
   1.381 +      }
   1.382 +      default:
   1.383 +        break;
   1.384 +    }
   1.385 +    bci += rc_instr_len(bci);
   1.386 +  }
   1.387 +}
   1.388 +
   1.389 +// The width of instruction at "pc" is changing by "delta".  Adjust the
   1.390 +// exception table, if any, of "rc->mb".
   1.391 +void Relocator::adjust_exception_table(int bci, int delta) {
   1.392 +  typeArrayOop table = method()->exception_table();
   1.393 +  for (int index = 0; index < table->length(); index +=4) {
   1.394 +    if (table->int_at(index) > bci) {
   1.395 +      table->int_at_put(index+0, table->int_at(index+0) + delta);
   1.396 +      table->int_at_put(index+1, table->int_at(index+1) + delta);
   1.397 +    } else if (bci < table->int_at(index+1)) {
   1.398 +      table->int_at_put(index+1, table->int_at(index+1) + delta);
   1.399 +    }
   1.400 +    if (table->int_at(index+2) > bci)
   1.401 +      table->int_at_put(index+2, table->int_at(index+2) + delta);
   1.402 +  }
   1.403 +}
   1.404 +
   1.405 +
   1.406 +// The width of instruction at "bci" is changing by "delta".  Adjust the line number table.
   1.407 +void Relocator::adjust_line_no_table(int bci, int delta) {
   1.408 +  if (method()->has_linenumber_table()) {
   1.409 +    CompressedLineNumberReadStream  reader(method()->compressed_linenumber_table());
   1.410 +    CompressedLineNumberWriteStream writer(64);  // plenty big for most line number tables
   1.411 +    while (reader.read_pair()) {
   1.412 +      int adjustment = (reader.bci() > bci) ? delta : 0;
   1.413 +      writer.write_pair(reader.bci() + adjustment, reader.line());
   1.414 +    }
   1.415 +    writer.write_terminator();
   1.416 +    set_compressed_line_number_table(writer.buffer());
   1.417 +    set_compressed_line_number_table_size(writer.position());
   1.418 +  }
   1.419 +}
   1.420 +
   1.421 +
   1.422 +// The width of instruction at "bci" is changing by "delta".  Adjust the local variable table.
   1.423 +void Relocator::adjust_local_var_table(int bci, int delta) {
   1.424 +  int localvariable_table_length = method()->localvariable_table_length();
   1.425 +  if (localvariable_table_length > 0) {
   1.426 +    LocalVariableTableElement* table = method()->localvariable_table_start();
   1.427 +    for (int i = 0; i < localvariable_table_length; i++) {
   1.428 +      u2 current_bci = table[i].start_bci;
   1.429 +      if (current_bci > bci) {
   1.430 +        table[i].start_bci = current_bci + delta;
   1.431 +      } else {
   1.432 +        u2 current_length = table[i].length;
   1.433 +        if (current_bci + current_length > bci) {
   1.434 +          table[i].length = current_length + delta;
   1.435 +        }
   1.436 +      }
   1.437 +    }
   1.438 +  }
   1.439 +}
   1.440 +
   1.441 +
   1.442 +bool Relocator::expand_code_array(int delta) {
   1.443 +  int length = MAX2(code_length() + delta, code_length() * (100+code_slop_pct()) / 100);
   1.444 +
   1.445 +  if (length > MAX_METHOD_LENGTH) {
   1.446 +    if (delta == 0 && code_length() <= MAX_METHOD_LENGTH) {
   1.447 +      length = MAX_METHOD_LENGTH;
   1.448 +    } else {
   1.449 +      return false;
   1.450 +    }
   1.451 +  }
   1.452 +
   1.453 +  unsigned char* new_code_array = NEW_RESOURCE_ARRAY(unsigned char, length);
   1.454 +  if (!new_code_array) return false;
   1.455 +
   1.456 +  // Expanding current array
   1.457 +  if (code_array() != NULL) {
   1.458 +    memcpy(new_code_array, code_array(), code_length());
   1.459 +  } else {
   1.460 +    // Initial copy. Copy directly from methodOop
   1.461 +    memcpy(new_code_array, method()->code_base(), code_length());
   1.462 +  }
   1.463 +
   1.464 +  set_code_array(new_code_array);
   1.465 +  set_code_array_length(length);
   1.466 +
   1.467 +  return true;
   1.468 +}
   1.469 +
   1.470 +
   1.471 +// The instruction at "bci", whose size is "ilen", is changing size by
   1.472 +// "delta".  Reallocate, move code, recalculate jumps, and enqueue
   1.473 +// change items as necessary.
   1.474 +bool Relocator::relocate_code(int bci, int ilen, int delta) {
   1.475 +  int next_bci = bci + ilen;
   1.476 +  if (delta > 0 && code_length() + delta > code_array_length())  {
   1.477 +    // Expand allocated code space, if necessary.
   1.478 +    if (!expand_code_array(delta)) {
   1.479 +          return false;
   1.480 +    }
   1.481 +  }
   1.482 +
   1.483 +  // We require 4-byte alignment of code arrays.
   1.484 +  assert(((intptr_t)code_array() & 3) == 0, "check code alignment");
   1.485 +  // Change jumps before doing the copying; this routine requires aligned switches.
   1.486 +  change_jumps(bci, delta);
   1.487 +
   1.488 +  // In case we have shrunken a tableswitch/lookupswitch statement, we store the last
   1.489 +  // bytes that get overwritten. We have to copy the bytes after the change_jumps method
   1.490 +  // has been called, since it is likly to update last offset in a tableswitch/lookupswitch
   1.491 +  if (delta < 0) {
   1.492 +    assert(delta>=-3, "we cannot overwrite more than 3 bytes");
   1.493 +    memcpy(_overwrite, addr_at(bci + ilen + delta), -delta);
   1.494 +  }
   1.495 +
   1.496 +  memmove(addr_at(next_bci + delta), addr_at(next_bci), code_length() - next_bci);
   1.497 +  set_code_length(code_length() + delta);
   1.498 +  // Also adjust exception tables...
   1.499 +  adjust_exception_table(bci, delta);
   1.500 +  // Line number tables...
   1.501 +  adjust_line_no_table(bci, delta);
   1.502 +  // And local variable table...
   1.503 +  adjust_local_var_table(bci, delta);
   1.504 +
   1.505 +  // Relocate the pending change stack...
   1.506 +  for (int j = 0; j < _changes->length(); j++) {
   1.507 +    ChangeItem* ci = _changes->at(j);
   1.508 +    ci->relocate(bci, delta);
   1.509 +  }
   1.510 +
   1.511 +  // Notify any listeners about code relocation
   1.512 +  notify(bci, delta, code_length());
   1.513 +
   1.514 +  return true;
   1.515 +}
   1.516 +
   1.517 +// relocate a general instruction. Called by ChangeWiden class
   1.518 +bool Relocator::handle_widen(int bci, int new_ilen, u_char inst_buffer[]) {
   1.519 +  int ilen = rc_instr_len(bci);
   1.520 +  if (!relocate_code(bci, ilen, new_ilen - ilen))
   1.521 +    return false;
   1.522 +
   1.523 +  // Insert new bytecode(s)
   1.524 +  for(int k = 0; k < new_ilen; k++) {
   1.525 +    code_at_put(bci + k, (Bytecodes::Code)inst_buffer[k]);
   1.526 +  }
   1.527 +
   1.528 +  return true;
   1.529 +}
   1.530 +
   1.531 +// handle jump_widen instruction. Called be ChangeJumpWiden class
   1.532 +bool Relocator::handle_jump_widen(int bci, int delta) {
   1.533 +  int ilen = rc_instr_len(bci);
   1.534 +
   1.535 +  Bytecodes::Code bc = code_at(bci);
   1.536 +  switch (bc) {
   1.537 +    case Bytecodes::_ifeq:
   1.538 +    case Bytecodes::_ifne:
   1.539 +    case Bytecodes::_iflt:
   1.540 +    case Bytecodes::_ifge:
   1.541 +    case Bytecodes::_ifgt:
   1.542 +    case Bytecodes::_ifle:
   1.543 +    case Bytecodes::_if_icmpeq:
   1.544 +    case Bytecodes::_if_icmpne:
   1.545 +    case Bytecodes::_if_icmplt:
   1.546 +    case Bytecodes::_if_icmpge:
   1.547 +    case Bytecodes::_if_icmpgt:
   1.548 +    case Bytecodes::_if_icmple:
   1.549 +    case Bytecodes::_if_acmpeq:
   1.550 +    case Bytecodes::_if_acmpne:
   1.551 +    case Bytecodes::_ifnull:
   1.552 +    case Bytecodes::_ifnonnull: {
   1.553 +      const int goto_length   = Bytecodes::length_for(Bytecodes::_goto);
   1.554 +
   1.555 +      // If 'if' points to the next bytecode after goto, it's already handled.
   1.556 +      // it shouldn't be.
   1.557 +      assert (short_at(bci+1) != ilen+goto_length, "if relocation already handled");
   1.558 +      assert(ilen == 3, "check length");
   1.559 +
   1.560 +      // Convert to 0 if <cond> goto 6
   1.561 +      //            3 _goto 11
   1.562 +      //            6 _goto_w <wide delta offset>
   1.563 +      //            11 <else code>
   1.564 +      const int goto_w_length = Bytecodes::length_for(Bytecodes::_goto_w);
   1.565 +      const int add_bci = goto_length + goto_w_length;
   1.566 +
   1.567 +      if (!relocate_code(bci, 3, /*delta*/add_bci)) return false;
   1.568 +
   1.569 +      // if bytecode points to goto_w instruction
   1.570 +      short_at_put(bci + 1, ilen + goto_length);
   1.571 +
   1.572 +      int cbci = bci + ilen;
   1.573 +      // goto around
   1.574 +      code_at_put(cbci, Bytecodes::_goto);
   1.575 +      short_at_put(cbci + 1, add_bci);
   1.576 +      // goto_w <wide delta>
   1.577 +      cbci = cbci + goto_length;
   1.578 +      code_at_put(cbci, Bytecodes::_goto_w);
   1.579 +      if (delta > 0) {
   1.580 +        delta += 2;                 // goto_w is 2 bytes more than "if" code
   1.581 +      } else {
   1.582 +        delta -= ilen+goto_length;  // branch starts at goto_w offset
   1.583 +      }
   1.584 +      int_at_put(cbci + 1, delta);
   1.585 +      break;
   1.586 +
   1.587 +      }
   1.588 +    case Bytecodes::_goto:
   1.589 +    case Bytecodes::_jsr:
   1.590 +      assert(ilen == 3, "check length");
   1.591 +
   1.592 +      if (!relocate_code(bci, 3, 2)) return false;
   1.593 +      if (bc == Bytecodes::_goto)
   1.594 +        code_at_put(bci, Bytecodes::_goto_w);
   1.595 +      else
   1.596 +        code_at_put(bci, Bytecodes::_jsr_w);
   1.597 +
   1.598 +      // If it's a forward jump, add 2 for the widening.
   1.599 +      if (delta > 0) delta += 2;
   1.600 +      int_at_put(bci + 1, delta);
   1.601 +      break;
   1.602 +
   1.603 +    default: ShouldNotReachHere();
   1.604 +  }
   1.605 +
   1.606 +  return true;
   1.607 +}
   1.608 +
   1.609 +// handle lookup/table switch instructions.  Called be ChangeSwitchPad class
   1.610 +bool Relocator::handle_switch_pad(int bci, int old_pad, bool is_lookup_switch) {
   1.611 +  int ilen = rc_instr_len(bci);
   1.612 +  int new_pad = align(bci+1) - (bci+1);
   1.613 +  int pad_delta = new_pad - old_pad;
   1.614 +  if (pad_delta != 0) {
   1.615 +    int len;
   1.616 +    if (!is_lookup_switch) {
   1.617 +      int low  = int_at(bci+1+old_pad+4);
   1.618 +      int high = int_at(bci+1+old_pad+8);
   1.619 +      len = high-low+1 + 3; // 3 for default, hi, lo.
   1.620 +    } else {
   1.621 +      int npairs = int_at(bci+1+old_pad+4);
   1.622 +      len = npairs*2 + 2; // 2 for default, npairs.
   1.623 +    }
   1.624 +    // Because "relocateCode" does a "changeJumps" loop,
   1.625 +    // which parses instructions to determine their length,
   1.626 +    // we need to call that before messing with the current
   1.627 +    // instruction.  Since it may also overwrite the current
   1.628 +    // instruction when moving down, remember the possibly
   1.629 +    // overwritten part.
   1.630 +
   1.631 +    // Move the code following the instruction...
   1.632 +    if (!relocate_code(bci, ilen, pad_delta)) return false;
   1.633 +
   1.634 +    if (pad_delta < 0) {
   1.635 +      // Move the shrunken instruction down.
   1.636 +      memmove(addr_at(bci + 1 + new_pad),
   1.637 +              addr_at(bci + 1 + old_pad),
   1.638 +              len * 4 + pad_delta);
   1.639 +      memmove(addr_at(bci + 1 + new_pad + len*4 + pad_delta),
   1.640 +              _overwrite, -pad_delta);
   1.641 +    } else {
   1.642 +      assert(pad_delta > 0, "check");
   1.643 +      // Move the expanded instruction up.
   1.644 +      memmove(addr_at(bci +1 + new_pad),
   1.645 +              addr_at(bci +1 + old_pad),
   1.646 +              len * 4);
   1.647 +    }
   1.648 +  }
   1.649 +  return true;
   1.650 +}

mercurial