duke@435: /* coleenp@4037: * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #ifndef SHARE_VM_PRIMS_METHODCOMPARATOR_HPP stefank@2314: #define SHARE_VM_PRIMS_METHODCOMPARATOR_HPP stefank@2314: stefank@2314: #include "interpreter/bytecodeStream.hpp" coleenp@4037: #include "oops/constantPool.hpp" coleenp@4037: #include "oops/method.hpp" stefank@2314: duke@435: class BciMap; duke@435: duke@435: // methodComparator provides an interface for determining if methods of duke@435: // different versions of classes are equivalent or switchable duke@435: duke@435: class MethodComparator { duke@435: private: duke@435: static BytecodeStream *_s_old, *_s_new; coleenp@4037: static ConstantPool* _old_cp; coleenp@4037: static ConstantPool* _new_cp; duke@435: static BciMap *_bci_map; duke@435: static bool _switchable_test; duke@435: static GrowableArray *_fwd_jmps; duke@435: duke@435: static bool args_same(Bytecodes::Code c_old, Bytecodes::Code c_new); jrose@2268: static bool pool_constants_same(int cpi_old, int cpi_new); coleenp@4037: static int check_stack_and_locals_size(Method* old_method, Method* new_method); duke@435: duke@435: public: duke@435: // Check if the new method is equivalent to the old one modulo constant pool (EMCP). duke@435: // Intuitive definition: two versions of the same method are EMCP, if they don't differ duke@435: // on the source code level. Practically, we check whether the only difference between duke@435: // method versions is some constantpool indices embedded into the bytecodes, and whether duke@435: // these indices eventually point to the same constants for both method versions. coleenp@4037: static bool methods_EMCP(Method* old_method, Method* new_method); duke@435: coleenp@4037: static bool methods_switchable(Method* old_method, Method* new_method, BciMap &bci_map); duke@435: }; duke@435: duke@435: duke@435: // ByteCode Index Map. For two versions of the same method, where the new version may contain duke@435: // fragments not found in the old version, provides a mapping from an index of a bytecode in duke@435: // the old method to the index of the same bytecode in the new method. duke@435: duke@435: class BciMap { duke@435: private: duke@435: int *_old_bci, *_new_st_bci, *_new_end_bci; duke@435: int _cur_size, _cur_pos; duke@435: int _pos; duke@435: duke@435: public: duke@435: BciMap() { duke@435: _cur_size = 50; duke@435: _old_bci = (int*) malloc(sizeof(int) * _cur_size); duke@435: _new_st_bci = (int*) malloc(sizeof(int) * _cur_size); duke@435: _new_end_bci = (int*) malloc(sizeof(int) * _cur_size); duke@435: _cur_pos = 0; duke@435: } duke@435: duke@435: ~BciMap() { duke@435: free(_old_bci); duke@435: free(_new_st_bci); duke@435: free(_new_end_bci); duke@435: } duke@435: duke@435: // Store the position of an added fragment, e.g. duke@435: // duke@435: // |<- old_bci duke@435: // ----------------------------------------- duke@435: // Old method |invokevirtual 5|aload 1|... duke@435: // ----------------------------------------- duke@435: // duke@435: // |<- new_st_bci |<- new_end_bci duke@435: // -------------------------------------------------------------------- duke@435: // New method |invokevirual 5|aload 2|invokevirtual 6|aload 1|... duke@435: // -------------------------------------------------------------------- duke@435: // ^^^^^^^^^^^^^^^^^^^^^^^^ duke@435: // Added fragment duke@435: duke@435: void store_fragment_location(int old_bci, int new_st_bci, int new_end_bci) { duke@435: if (_cur_pos == _cur_size) { duke@435: _cur_size += 10; duke@435: _old_bci = (int*) realloc(_old_bci, sizeof(int) * _cur_size); duke@435: _new_st_bci = (int*) realloc(_new_st_bci, sizeof(int) * _cur_size); duke@435: _new_end_bci = (int*) realloc(_new_end_bci, sizeof(int) * _cur_size); duke@435: } duke@435: _old_bci[_cur_pos] = old_bci; duke@435: _new_st_bci[_cur_pos] = new_st_bci; duke@435: _new_end_bci[_cur_pos] = new_end_bci; duke@435: _cur_pos++; duke@435: } duke@435: duke@435: int new_bci_for_old(int old_bci) { duke@435: if (_cur_pos == 0 || old_bci < _old_bci[0]) return old_bci; duke@435: _pos = 1; duke@435: while (_pos < _cur_pos && old_bci >= _old_bci[_pos]) duke@435: _pos++; duke@435: return _new_end_bci[_pos-1] + (old_bci - _old_bci[_pos-1]); duke@435: } duke@435: duke@435: // Test if two indexes - one in the old method and another in the new one - correspond duke@435: // to the same bytecode duke@435: bool old_and_new_locations_same(int old_dest_bci, int new_dest_bci) { duke@435: if (new_bci_for_old(old_dest_bci) == new_dest_bci) duke@435: return true; duke@435: else if (_old_bci[_pos-1] == old_dest_bci) duke@435: return (new_dest_bci == _new_st_bci[_pos-1]); duke@435: else return false; duke@435: } duke@435: }; stefank@2314: stefank@2314: #endif // SHARE_VM_PRIMS_METHODCOMPARATOR_HPP