methodComparator.cpp revision 844:bd02caa94611
1249259Sdim/* 2249259Sdim * Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved. 3353358Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4353358Sdim * 5353358Sdim * This code is free software; you can redistribute it and/or modify it 6249259Sdim * under the terms of the GNU General Public License version 2 only, as 7249259Sdim * published by the Free Software Foundation. 8249259Sdim * 9249259Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 10341825Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11249259Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12249259Sdim * version 2 for more details (a copy is included in the LICENSE file that 13249259Sdim * accompanied this code). 14353358Sdim * 15249259Sdim * You should have received a copy of the GNU General Public License version 16249259Sdim * 2 along with this work; if not, write to the Free Software Foundation, 17276479Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18309124Sdim * 19249259Sdim * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20249259Sdim * CA 95054 USA or visit www.sun.com if you need additional information or 21249259Sdim * have any questions. 22249259Sdim * 23249259Sdim */ 24249259Sdim 25249259Sdim# include "incls/_precompiled.incl" 26276479Sdim# include "incls/_methodComparator.cpp.incl" 27276479Sdim 28249259SdimBytecodeStream *MethodComparator::_s_old; 29249259SdimBytecodeStream *MethodComparator::_s_new; 30249259SdimconstantPoolOop MethodComparator::_old_cp; 31249259SdimconstantPoolOop MethodComparator::_new_cp; 32341825SdimBciMap *MethodComparator::_bci_map; 33249259Sdimbool MethodComparator::_switchable_test; 34249259SdimGrowableArray<int> *MethodComparator::_fwd_jmps; 35276479Sdim 36276479Sdimbool MethodComparator::methods_EMCP(methodOop old_method, methodOop new_method) { 37249259Sdim if (old_method->code_size() != new_method->code_size()) 38280031Sdim return false; 39280031Sdim if (check_stack_and_locals_size(old_method, new_method) != 0) { 40280031Sdim // RC_TRACE macro has an embedded ResourceMark 41249259Sdim RC_TRACE(0x00800000, ("Methods %s non-comparable with diagnosis %d", 42249259Sdim old_method->name()->as_C_string(), 43249259Sdim check_stack_and_locals_size(old_method, new_method))); 44280031Sdim return false; 45280031Sdim } 46249259Sdim 47280031Sdim _old_cp = old_method->constants(); 48280031Sdim _new_cp = new_method->constants(); 49249259Sdim BytecodeStream s_old(old_method); 50249259Sdim BytecodeStream s_new(new_method); 51249259Sdim _s_old = &s_old; 52280031Sdim _s_new = &s_new; 53249259Sdim _switchable_test = false; 54249259Sdim Bytecodes::Code c_old, c_new; 55249259Sdim 56280031Sdim while ((c_old = s_old.next()) >= 0) { 57280031Sdim if ((c_new = s_new.next()) < 0 || c_old != c_new) 58249259Sdim return false; 59280031Sdim 60280031Sdim if (! args_same(c_old, c_new)) 61249259Sdim return false; 62249259Sdim } 63249259Sdim return true; 64280031Sdim} 65280031Sdim 66249259Sdim 67249259Sdimbool MethodComparator::methods_switchable(methodOop old_method, methodOop new_method, 68249259Sdim BciMap &bci_map) { 69249259Sdim if (old_method->code_size() > new_method->code_size()) 70249259Sdim // Something has definitely been deleted in the new method, compared to the old one. 71276479Sdim return false; 72276479Sdim 73249259Sdim if (! check_stack_and_locals_size(old_method, new_method)) 74249259Sdim return false; 75249259Sdim 76249259Sdim _old_cp = old_method->constants(); 77249259Sdim _new_cp = new_method->constants(); 78249259Sdim BytecodeStream s_old(old_method); 79249259Sdim BytecodeStream s_new(new_method); 80249259Sdim _s_old = &s_old; 81249259Sdim _s_new = &s_new; 82249259Sdim _bci_map = &bci_map; 83249259Sdim _switchable_test = true; 84249259Sdim GrowableArray<int> fwd_jmps(16); 85249259Sdim _fwd_jmps = &fwd_jmps; 86249259Sdim Bytecodes::Code c_old, c_new; 87249259Sdim 88251662Sdim while ((c_old = s_old.next()) >= 0) { 89251662Sdim if ((c_new = s_new.next()) < 0) 90249259Sdim return false; 91249259Sdim if (! (c_old == c_new && args_same(c_old, c_new))) { 92249259Sdim int old_bci = s_old.bci(); 93249259Sdim int new_st_bci = s_new.bci(); 94249259Sdim bool found_match = false; 95249259Sdim do { 96249259Sdim c_new = s_new.next(); 97249259Sdim if (c_new == c_old && args_same(c_old, c_new)) { 98249259Sdim found_match = true; 99249259Sdim break; 100249259Sdim } 101249259Sdim } while (c_new >= 0); 102249259Sdim if (! found_match) 103249259Sdim return false; 104249259Sdim int new_end_bci = s_new.bci(); 105249259Sdim bci_map.store_fragment_location(old_bci, new_st_bci, new_end_bci); 106249259Sdim } 107249259Sdim } 108249259Sdim 109249259Sdim // Now we can test all forward jumps 110249259Sdim for (int i = 0; i < fwd_jmps.length() / 2; i++) { 111249259Sdim if (! bci_map.old_and_new_locations_same(fwd_jmps.at(i*2), fwd_jmps.at(i*2+1))) { 112249259Sdim RC_TRACE(0x00800000, 113249259Sdim ("Fwd jump miss: old dest = %d, calc new dest = %d, act new dest = %d", 114249259Sdim fwd_jmps.at(i*2), bci_map.new_bci_for_old(fwd_jmps.at(i*2)), 115249259Sdim fwd_jmps.at(i*2+1))); 116249259Sdim return false; 117249259Sdim } 118249259Sdim } 119249259Sdim 120249259Sdim return true; 121249259Sdim} 122249259Sdim 123249259Sdim 124249259Sdimbool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) { 125249259Sdim // BytecodeStream returns the correct standard Java bytecodes for various "fast" 126249259Sdim // bytecode versions, so we don't have to bother about them here.. 127249259Sdim switch (c_old) { 128249259Sdim case Bytecodes::_new : // fall through 129249259Sdim case Bytecodes::_anewarray : // fall through 130249259Sdim case Bytecodes::_multianewarray : // fall through 131249259Sdim case Bytecodes::_checkcast : // fall through 132249259Sdim case Bytecodes::_instanceof : { 133249259Sdim u2 cpi_old = _s_old->get_index_big(); 134249259Sdim u2 cpi_new = _s_new->get_index_big(); 135249259Sdim if ((_old_cp->klass_at_noresolve(cpi_old) != _new_cp->klass_at_noresolve(cpi_new))) 136249259Sdim return false; 137249259Sdim if (c_old == Bytecodes::_multianewarray && 138249259Sdim *(jbyte*)(_s_old->bcp() + 3) != *(jbyte*)(_s_new->bcp() + 3)) 139249259Sdim return false; 140249259Sdim break; 141249259Sdim } 142249259Sdim 143249259Sdim case Bytecodes::_getstatic : // fall through 144249259Sdim case Bytecodes::_putstatic : // fall through 145249259Sdim case Bytecodes::_getfield : // fall through 146249259Sdim case Bytecodes::_putfield : // fall through 147249259Sdim case Bytecodes::_invokevirtual : // fall through 148249259Sdim case Bytecodes::_invokespecial : // fall through 149249259Sdim case Bytecodes::_invokestatic : // fall through 150249259Sdim case Bytecodes::_invokeinterface : { 151249259Sdim u2 cpci_old = _s_old->get_index_int(); 152249259Sdim u2 cpci_new = _s_new->get_index_int(); 153249259Sdim // Check if the names of classes, field/method names and signatures at these indexes 154249259Sdim // are the same. Indices which are really into constantpool cache (rather than constant 155249259Sdim // pool itself) are accepted by the constantpool query routines below. 156249259Sdim if ((_old_cp->klass_ref_at_noresolve(cpci_old) != _new_cp->klass_ref_at_noresolve(cpci_new)) || 157249259Sdim (_old_cp->name_ref_at(cpci_old) != _new_cp->name_ref_at(cpci_new)) || 158249259Sdim (_old_cp->signature_ref_at(cpci_old) != _new_cp->signature_ref_at(cpci_new))) 159249259Sdim return false; 160249259Sdim break; 161249259Sdim } 162249259Sdim 163249259Sdim case Bytecodes::_ldc : // fall through 164249259Sdim case Bytecodes::_ldc_w : { 165249259Sdim u2 cpi_old, cpi_new; 166249259Sdim if (c_old == Bytecodes::_ldc) { 167249259Sdim cpi_old = _s_old->bcp()[1]; 168249259Sdim cpi_new = _s_new->bcp()[1]; 169249259Sdim } else { 170249259Sdim cpi_old = _s_old->get_index_big(); 171249259Sdim cpi_new = _s_new->get_index_big(); 172249259Sdim } 173249259Sdim constantTag tag_old = _old_cp->tag_at(cpi_old); 174249259Sdim constantTag tag_new = _new_cp->tag_at(cpi_new); 175249259Sdim if (tag_old.is_int() || tag_old.is_float()) { 176249259Sdim if (tag_old.value() != tag_new.value()) 177249259Sdim return false; 178249259Sdim if (tag_old.is_int()) { 179249259Sdim if (_old_cp->int_at(cpi_old) != _new_cp->int_at(cpi_new)) 180249259Sdim return false; 181249259Sdim } else { 182249259Sdim if (_old_cp->float_at(cpi_old) != _new_cp->float_at(cpi_new)) 183249259Sdim return false; 184249259Sdim } 185249259Sdim } else if (tag_old.is_string() || tag_old.is_unresolved_string()) { 186249259Sdim if (! (tag_new.is_unresolved_string() || tag_new.is_string())) 187249259Sdim return false; 188249259Sdim if (strcmp(_old_cp->string_at_noresolve(cpi_old), 189249259Sdim _new_cp->string_at_noresolve(cpi_new)) != 0) 190249259Sdim return false; 191249259Sdim } else { // tag_old should be klass - 4881222 192249259Sdim if (! (tag_new.is_unresolved_klass() || tag_new.is_klass())) 193249259Sdim return false; 194249259Sdim if (_old_cp->klass_at_noresolve(cpi_old) != 195249259Sdim _new_cp->klass_at_noresolve(cpi_new)) 196249259Sdim return false; 197249259Sdim } 198249259Sdim break; 199249259Sdim } 200249259Sdim 201249259Sdim case Bytecodes::_ldc2_w : { 202249259Sdim u2 cpi_old = _s_old->get_index_big(); 203249259Sdim u2 cpi_new = _s_new->get_index_big(); 204249259Sdim constantTag tag_old = _old_cp->tag_at(cpi_old); 205249259Sdim constantTag tag_new = _new_cp->tag_at(cpi_new); 206288943Sdim if (tag_old.value() != tag_new.value()) 207249259Sdim return false; 208249259Sdim if (tag_old.is_long()) { 209249259Sdim if (_old_cp->long_at(cpi_old) != _new_cp->long_at(cpi_new)) 210249259Sdim return false; 211249259Sdim } else { 212249259Sdim if (_old_cp->double_at(cpi_old) != _new_cp->double_at(cpi_new)) 213249259Sdim return false; 214249259Sdim } 215249259Sdim break; 216249259Sdim } 217249259Sdim 218288943Sdim case Bytecodes::_bipush : 219249259Sdim if (_s_old->bcp()[1] != _s_new->bcp()[1]) 220249259Sdim return false; 221249259Sdim break; 222249259Sdim 223249259Sdim case Bytecodes::_sipush : 224249259Sdim if (_s_old->get_index_big() != _s_new->get_index_big()) 225249259Sdim return false; 226296417Sdim break; 227249259Sdim 228249259Sdim case Bytecodes::_aload : // fall through 229288943Sdim case Bytecodes::_astore : // fall through 230249259Sdim case Bytecodes::_dload : // fall through 231249259Sdim case Bytecodes::_dstore : // fall through 232249259Sdim case Bytecodes::_fload : // fall through 233251662Sdim case Bytecodes::_fstore : // fall through 234251662Sdim case Bytecodes::_iload : // fall through 235288943Sdim case Bytecodes::_istore : // fall through 236249259Sdim case Bytecodes::_lload : // fall through 237249259Sdim case Bytecodes::_lstore : // fall through 238249259Sdim case Bytecodes::_ret : 239249259Sdim if (_s_old->is_wide() != _s_new->is_wide()) 240249259Sdim return false; 241249259Sdim if (_s_old->get_index() != _s_new->get_index()) 242249259Sdim return false; 243249259Sdim break; 244249259Sdim 245249259Sdim case Bytecodes::_goto : // fall through 246249259Sdim case Bytecodes::_if_acmpeq : // fall through 247249259Sdim case Bytecodes::_if_acmpne : // fall through 248249259Sdim case Bytecodes::_if_icmpeq : // fall through 249249259Sdim case Bytecodes::_if_icmpne : // fall through 250249259Sdim case Bytecodes::_if_icmplt : // fall through 251249259Sdim case Bytecodes::_if_icmpge : // fall through 252249259Sdim case Bytecodes::_if_icmpgt : // fall through 253249259Sdim case Bytecodes::_if_icmple : // fall through 254249259Sdim case Bytecodes::_ifeq : // fall through 255249259Sdim case Bytecodes::_ifne : // fall through 256249259Sdim case Bytecodes::_iflt : // fall through 257249259Sdim case Bytecodes::_ifge : // fall through 258249259Sdim case Bytecodes::_ifgt : // fall through 259249259Sdim case Bytecodes::_ifle : // fall through 260249259Sdim case Bytecodes::_ifnonnull : // fall through 261249259Sdim case Bytecodes::_ifnull : // fall through 262249259Sdim case Bytecodes::_jsr : { 263249259Sdim short old_ofs = (short) _s_old->get_index_big(); 264249259Sdim short new_ofs = (short) _s_new->get_index_big(); 265249259Sdim if (_switchable_test) { 266249259Sdim int old_dest = _s_old->bci() + old_ofs; 267249259Sdim int new_dest = _s_new->bci() + new_ofs; 268249259Sdim if (old_ofs < 0 && new_ofs < 0) { 269249259Sdim if (! _bci_map->old_and_new_locations_same(old_dest, new_dest)) 270249259Sdim return false; 271249259Sdim } else if (old_ofs > 0 && new_ofs > 0) { 272249259Sdim _fwd_jmps->append(old_dest); 273249259Sdim _fwd_jmps->append(new_dest); 274249259Sdim } else { 275249259Sdim return false; 276249259Sdim } 277249259Sdim } else { 278249259Sdim if (old_ofs != new_ofs) 279249259Sdim return false; 280249259Sdim } 281249259Sdim break; 282249259Sdim } 283249259Sdim 284249259Sdim case Bytecodes::_iinc : 285249259Sdim if (_s_old->is_wide() != _s_new->is_wide()) 286249259Sdim return false; 287249259Sdim if (! _s_old->is_wide()) { 288249259Sdim if (_s_old->get_index_big() != _s_new->get_index_big()) 289249259Sdim return false; 290249259Sdim } else { 291249259Sdim if (Bytes::get_Java_u4(_s_old->bcp() + 1) != Bytes::get_Java_u4(_s_new->bcp() + 1)) 292249259Sdim return false; 293249259Sdim } 294249259Sdim break; 295249259Sdim 296249259Sdim case Bytecodes::_goto_w : // fall through 297249259Sdim case Bytecodes::_jsr_w : { 298249259Sdim int old_ofs = (int) Bytes::get_Java_u4(_s_old->bcp() + 1); 299249259Sdim int new_ofs = (int) Bytes::get_Java_u4(_s_new->bcp() + 1); 300249259Sdim if (_switchable_test) { 301249259Sdim int old_dest = _s_old->bci() + old_ofs; 302249259Sdim int new_dest = _s_new->bci() + new_ofs; 303249259Sdim if (old_ofs < 0 && new_ofs < 0) { 304249259Sdim if (! _bci_map->old_and_new_locations_same(old_dest, new_dest)) 305249259Sdim return false; 306249259Sdim } else if (old_ofs > 0 && new_ofs > 0) { 307249259Sdim _fwd_jmps->append(old_dest); 308249259Sdim _fwd_jmps->append(new_dest); 309249259Sdim } else { 310249259Sdim return false; 311249259Sdim } 312249259Sdim } else { 313249259Sdim if (old_ofs != new_ofs) 314249259Sdim return false; 315249259Sdim } 316249259Sdim break; 317249259Sdim } 318249259Sdim 319249259Sdim case Bytecodes::_lookupswitch : // fall through 320249259Sdim case Bytecodes::_tableswitch : { 321249259Sdim if (_switchable_test) { 322249259Sdim address aligned_bcp_old = (address) round_to((intptr_t)_s_old->bcp() + 1, jintSize); 323249259Sdim address aligned_bcp_new = (address) round_to((intptr_t)_s_new->bcp() + 1, jintSize); 324249259Sdim int default_old = (int) Bytes::get_Java_u4(aligned_bcp_old); 325249259Sdim int default_new = (int) Bytes::get_Java_u4(aligned_bcp_new); 326249259Sdim _fwd_jmps->append(_s_old->bci() + default_old); 327249259Sdim _fwd_jmps->append(_s_new->bci() + default_new); 328249259Sdim if (c_old == Bytecodes::_lookupswitch) { 329249259Sdim int npairs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + jintSize); 330249259Sdim int npairs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + jintSize); 331249259Sdim if (npairs_old != npairs_new) 332249259Sdim return false; 333249259Sdim for (int i = 0; i < npairs_old; i++) { 334249259Sdim int match_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (2+2*i)*jintSize); 335249259Sdim int match_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (2+2*i)*jintSize); 336249259Sdim if (match_old != match_new) 337249259Sdim return false; 338249259Sdim int ofs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (2+2*i+1)*jintSize); 339249259Sdim int ofs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (2+2*i+1)*jintSize); 340249259Sdim _fwd_jmps->append(_s_old->bci() + ofs_old); 341249259Sdim _fwd_jmps->append(_s_new->bci() + ofs_new); 342249259Sdim } 343249259Sdim } else if (c_old == Bytecodes::_tableswitch) { 344249259Sdim int lo_old = (int) Bytes::get_Java_u4(aligned_bcp_old + jintSize); 345249259Sdim int lo_new = (int) Bytes::get_Java_u4(aligned_bcp_new + jintSize); 346249259Sdim if (lo_old != lo_new) 347249259Sdim return false; 348249259Sdim int hi_old = (int) Bytes::get_Java_u4(aligned_bcp_old + 2*jintSize); 349249259Sdim int hi_new = (int) Bytes::get_Java_u4(aligned_bcp_new + 2*jintSize); 350249259Sdim if (hi_old != hi_new) 351249259Sdim return false; 352249259Sdim for (int i = 0; i < hi_old - lo_old + 1; i++) { 353249259Sdim int ofs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (3+i)*jintSize); 354249259Sdim int ofs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (3+i)*jintSize); 355249259Sdim _fwd_jmps->append(_s_old->bci() + ofs_old); 356249259Sdim _fwd_jmps->append(_s_new->bci() + ofs_new); 357249259Sdim } 358249259Sdim } 359249259Sdim } else { // !_switchable_test, can use fast rough compare 360249259Sdim int len_old = _s_old->next_bcp() - _s_old->bcp(); 361249259Sdim int len_new = _s_new->next_bcp() - _s_new->bcp(); 362249259Sdim if (len_old != len_new) 363249259Sdim return false; 364288943Sdim if (memcmp(_s_old->bcp(), _s_new->bcp(), len_old) != 0) 365249259Sdim return false; 366249259Sdim } 367249259Sdim break; 368249259Sdim } 369249259Sdim } 370249259Sdim 371249259Sdim return true; 372249259Sdim} 373249259Sdim 374249259Sdim 375249259Sdimint MethodComparator::check_stack_and_locals_size(methodOop old_method, methodOop new_method) { 376249259Sdim if (old_method->max_stack() != new_method->max_stack()) { 377249259Sdim return 1; 378249259Sdim } else if (old_method->max_locals() != new_method->max_locals()) { 379249259Sdim return 2; 380249259Sdim } else if (old_method->size_of_parameters() != new_method->size_of_parameters()) { 381249259Sdim return 3; 382249259Sdim } else return 0; 383249259Sdim} 384249259Sdim