bytecodeStream.hpp revision 1472:c18cbe5936b8
1292934Sdim/* 2292934Sdim * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. 3292934Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4292934Sdim * 5292934Sdim * This code is free software; you can redistribute it and/or modify it 6292934Sdim * under the terms of the GNU General Public License version 2 only, as 7292934Sdim * published by the Free Software Foundation. 8292934Sdim * 9321369Sdim * This code is distributed in the hope that it will be useful, but WITHOUT 10321369Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11321369Sdim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12321369Sdim * version 2 for more details (a copy is included in the LICENSE file that 13321369Sdim * accompanied this code). 14321369Sdim * 15321369Sdim * You should have received a copy of the GNU General Public License version 16321369Sdim * 2 along with this work; if not, write to the Free Software Foundation, 17321369Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18321369Sdim * 19321369Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20321369Sdim * or visit www.oracle.com if you need additional information or have any 21321369Sdim * questions. 22321369Sdim * 23321369Sdim */ 24321369Sdim 25292934Sdim// A BytecodeStream is used for fast iteration over the bytecodes 26292934Sdim// of a methodOop. 27292934Sdim// 28292934Sdim// Usage: 29321369Sdim// 30303239Sdim// BytecodeStream s(method); 31292934Sdim// Bytecodes::Code c; 32303239Sdim// while ((c = s.next()) >= 0) { 33303239Sdim// ... 34314564Sdim// } 35321369Sdim// 36321369Sdim// A RawBytecodeStream is a simple version of BytecodeStream. 37303239Sdim// It is used ONLY when we know the bytecodes haven't been rewritten 38292934Sdim// yet, such as in the rewriter or the verifier. Currently only the 39321369Sdim// verifier uses this class. 40292934Sdim 41314564Sdimclass RawBytecodeStream: StackObj { 42292934Sdim protected: 43314564Sdim // stream buffer 44303239Sdim methodHandle _method; // read from method directly 45292934Sdim 46303239Sdim // reading position 47314564Sdim int _bci; // bci if current bytecode 48321369Sdim int _next_bci; // bci of next bytecode 49314564Sdim int _end_bci; // bci after the current iteration interval 50314564Sdim 51303239Sdim // last bytecode read 52292934Sdim Bytecodes::Code _code; 53303239Sdim bool _is_wide; 54292934Sdim 55292934Sdim public: 56292934Sdim // Construction 57292934Sdim RawBytecodeStream(methodHandle method) : _method(method) { 58292934Sdim set_interval(0, _method->code_size()); 59303239Sdim } 60292934Sdim 61292934Sdim // Iteration control 62303239Sdim void set_interval(int beg_bci, int end_bci) { 63292934Sdim // iterate over the interval [beg_bci, end_bci) 64303239Sdim assert(0 <= beg_bci && beg_bci <= method()->code_size(), "illegal beg_bci"); 65303239Sdim assert(0 <= end_bci && end_bci <= method()->code_size(), "illegal end_bci"); 66292934Sdim // setup of iteration pointers 67314564Sdim _bci = beg_bci; 68314564Sdim _next_bci = beg_bci; 69314564Sdim _end_bci = end_bci; 70314564Sdim } 71321369Sdim void set_start (int beg_bci) { 72321369Sdim set_interval(beg_bci, _method->code_size()); 73314564Sdim } 74314564Sdim 75314564Sdim // Iteration 76303239Sdim // Use raw_next() rather than next() for faster method reference 77321369Sdim Bytecodes::Code raw_next() { 78314564Sdim Bytecodes::Code code; 79303239Sdim // set reading position 80314564Sdim _bci = _next_bci; 81314564Sdim assert(!is_last_bytecode(), "caller should check is_last_bytecode()"); 82321369Sdim 83321369Sdim address bcp = RawBytecodeStream::bcp(); 84303239Sdim code = Bytecodes::code_or_bp_at(bcp); 85314564Sdim 86314564Sdim // set next bytecode position 87314564Sdim int l = Bytecodes::length_for(code); 88292934Sdim if (l > 0 && (_bci + l) <= _end_bci) { 89292934Sdim assert(code != Bytecodes::_wide && code != Bytecodes::_tableswitch 90303239Sdim && code != Bytecodes::_lookupswitch, "can't be special bytecode"); 91314564Sdim _is_wide = false; 92314564Sdim _next_bci += l; 93314564Sdim _code = code; 94314564Sdim return code; 95303239Sdim } else if (code == Bytecodes::_wide && _bci + 1 >= _end_bci) { 96314564Sdim return Bytecodes::_illegal; 97314564Sdim } else { 98303239Sdim return raw_next_special(code); 99303239Sdim } 100303239Sdim } 101314564Sdim Bytecodes::Code raw_next_special(Bytecodes::Code code); 102319957Semaste 103303239Sdim // Stream attributes 104321369Sdim methodHandle method() const { return _method; } 105321369Sdim 106303239Sdim int bci() const { return _bci; } 107303239Sdim int next_bci() const { return _next_bci; } 108303239Sdim int end_bci() const { return _end_bci; } 109303239Sdim 110314564Sdim Bytecodes::Code code() const { return _code; } 111303239Sdim bool is_wide() const { return _is_wide; } 112314564Sdim int instruction_size() const { return (_next_bci - _bci); } 113303239Sdim bool is_last_bytecode() const { return _next_bci >= _end_bci; } 114303239Sdim 115303239Sdim address bcp() const { return method()->code_base() + _bci; } 116303239Sdim address next_bcp() { return method()->code_base() + _next_bci; } 117314564Sdim 118303239Sdim // State changes 119314564Sdim void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci"); _next_bci = bci; } 120303239Sdim 121314564Sdim // Bytecode-specific attributes 122292934Sdim int dest() const { return bci() + (short)Bytes::get_Java_u2(bcp() + 1); } 123292934Sdim int dest_w() const { return bci() + (int )Bytes::get_Java_u4(bcp() + 1); } 124293258Sdim 125293258Sdim // Unsigned indices, widening 126321369Sdim int get_index() const { assert_index_size(is_wide() ? 2 : 1); 127321369Sdim return (is_wide()) ? Bytes::get_Java_u2(bcp() + 2) : bcp()[1]; } 128303239Sdim int get_index_big() const { assert_index_size(2); 129314564Sdim return (int)Bytes::get_Java_u2(bcp() + 1); } 130314564Sdim int get_index_int() const { return has_giant_index() ? get_index_giant() : get_index_big(); } 131293258Sdim int get_index_giant() const { assert_index_size(4); return Bytes::get_native_u4(bcp() + 1); } 132321369Sdim int has_giant_index() const { return (code() == Bytecodes::_invokedynamic); } 133314564Sdim 134303239Sdim private: 135314564Sdim void assert_index_size(int required_size) const { 136314564Sdim#ifdef ASSERT 137314564Sdim int isize = instruction_size() - (int)_is_wide - 1; 138303239Sdim if (isize == 2 && code() == Bytecodes::_iinc) 139303239Sdim isize = 1; 140314564Sdim else if (isize <= 2) 141314564Sdim ; // no change 142321369Sdim else if (has_giant_index()) 143293258Sdim isize = 4; 144303239Sdim else 145314564Sdim isize = 2; 146314564Sdim assert(isize = required_size, "wrong index size"); 147303239Sdim#endif 148303239Sdim } 149303239Sdim}; 150314564Sdim 151303239Sdim// In BytecodeStream, non-java bytecodes will be translated into the 152293258Sdim// corresponding java bytecodes. 153293258Sdim 154293258Sdimclass BytecodeStream: public RawBytecodeStream { 155321369Sdim public: 156321369Sdim // Construction 157303239Sdim BytecodeStream(methodHandle method) : RawBytecodeStream(method) { } 158292934Sdim 159303239Sdim // Iteration 160303239Sdim Bytecodes::Code next() { 161303239Sdim Bytecodes::Code code; 162303239Sdim // set reading position 163303239Sdim _bci = _next_bci; 164314564Sdim if (is_last_bytecode()) { 165314564Sdim // indicate end of bytecode stream 166314564Sdim code = Bytecodes::_illegal; 167314564Sdim } else { 168314564Sdim // get bytecode 169292934Sdim address bcp = BytecodeStream::bcp(); 170292934Sdim code = Bytecodes::java_code_at(bcp); 171303239Sdim // set next bytecode position 172292934Sdim // 173321369Sdim // note that we cannot advance before having the 174321369Sdim // tty bytecode otherwise the stepping is wrong! 175314564Sdim // (carefull: length_for(...) must be used first!) 176321369Sdim int l = Bytecodes::length_for(code); 177321369Sdim if (l == 0) l = Bytecodes::length_at(bcp); 178292934Sdim _next_bci += l; 179292934Sdim assert(_bci < _next_bci, "length must be > 0"); 180321369Sdim // set attributes 181321369Sdim _is_wide = false; 182321369Sdim // check for special (uncommon) cases 183321369Sdim if (code == Bytecodes::_wide) { 184321369Sdim code = (Bytecodes::Code)bcp[1]; 185321369Sdim _is_wide = true; 186321369Sdim } 187321369Sdim assert(Bytecodes::is_java_code(code), "sanity check"); 188321369Sdim } 189321369Sdim _code = code; 190321369Sdim return _code; 191321369Sdim } 192321369Sdim 193321369Sdim bool is_active_breakpoint() const { return Bytecodes::is_active_breakpoint_at(bcp()); } 194321369Sdim}; 195321369Sdim