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