aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #ifndef SHARE_VM_INTERPRETER_BYTECODESTREAM_HPP aoqi@0: #define SHARE_VM_INTERPRETER_BYTECODESTREAM_HPP aoqi@0: aoqi@0: #include "interpreter/bytecode.hpp" aoqi@0: #include "memory/allocation.hpp" aoqi@0: #include "oops/method.hpp" aoqi@0: #include "runtime/handles.inline.hpp" aoqi@0: #ifdef TARGET_ARCH_x86 aoqi@0: # include "bytes_x86.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_ARCH_sparc aoqi@0: # include "bytes_sparc.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_ARCH_zero aoqi@0: # include "bytes_zero.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_ARCH_arm aoqi@0: # include "bytes_arm.hpp" aoqi@0: #endif aoqi@0: #ifdef TARGET_ARCH_ppc aoqi@0: # include "bytes_ppc.hpp" aoqi@0: #endif aoqi@0: aoqi@0: // A BytecodeStream is used for fast iteration over the bytecodes aoqi@0: // of a Method*. aoqi@0: // aoqi@0: // Usage: aoqi@0: // aoqi@0: // BytecodeStream s(method); aoqi@0: // Bytecodes::Code c; aoqi@0: // while ((c = s.next()) >= 0) { aoqi@0: // ... aoqi@0: // } aoqi@0: aoqi@0: // A RawBytecodeStream is a simple version of BytecodeStream. aoqi@0: // It is used ONLY when we know the bytecodes haven't been rewritten aoqi@0: // yet, such as in the rewriter or the verifier. aoqi@0: aoqi@0: // Here is the common base class for both RawBytecodeStream and BytecodeStream: aoqi@0: class BaseBytecodeStream: StackObj { aoqi@0: protected: aoqi@0: // stream buffer aoqi@0: methodHandle _method; // read from method directly aoqi@0: aoqi@0: // reading position aoqi@0: int _bci; // bci if current bytecode aoqi@0: int _next_bci; // bci of next bytecode aoqi@0: int _end_bci; // bci after the current iteration interval aoqi@0: aoqi@0: // last bytecode read aoqi@0: Bytecodes::Code _raw_code; aoqi@0: bool _is_wide; aoqi@0: bool _is_raw; // false in 'cooked' BytecodeStream aoqi@0: aoqi@0: // Construction aoqi@0: BaseBytecodeStream(methodHandle method) : _method(method) { aoqi@0: set_interval(0, _method->code_size()); aoqi@0: _is_raw = false; aoqi@0: } aoqi@0: aoqi@0: public: aoqi@0: // Iteration control aoqi@0: void set_interval(int beg_bci, int end_bci) { aoqi@0: // iterate over the interval [beg_bci, end_bci) aoqi@0: assert(0 <= beg_bci && beg_bci <= method()->code_size(), "illegal beg_bci"); aoqi@0: assert(0 <= end_bci && end_bci <= method()->code_size(), "illegal end_bci"); aoqi@0: // setup of iteration pointers aoqi@0: _bci = beg_bci; aoqi@0: _next_bci = beg_bci; aoqi@0: _end_bci = end_bci; aoqi@0: } aoqi@0: void set_start (int beg_bci) { aoqi@0: set_interval(beg_bci, _method->code_size()); aoqi@0: } aoqi@0: aoqi@0: bool is_raw() const { return _is_raw; } aoqi@0: aoqi@0: // Stream attributes aoqi@0: methodHandle method() const { return _method; } aoqi@0: aoqi@0: int bci() const { return _bci; } aoqi@0: int next_bci() const { return _next_bci; } aoqi@0: int end_bci() const { return _end_bci; } aoqi@0: aoqi@0: Bytecodes::Code raw_code() const { return _raw_code; } aoqi@0: bool is_wide() const { return _is_wide; } aoqi@0: int instruction_size() const { return (_next_bci - _bci); } aoqi@0: bool is_last_bytecode() const { return _next_bci >= _end_bci; } aoqi@0: aoqi@0: address bcp() const { return method()->code_base() + _bci; } aoqi@0: Bytecode bytecode() const { return Bytecode(_method(), bcp()); } aoqi@0: aoqi@0: // State changes aoqi@0: void set_next_bci(int bci) { assert(0 <= bci && bci <= method()->code_size(), "illegal bci"); _next_bci = bci; } aoqi@0: aoqi@0: // Bytecode-specific attributes aoqi@0: int dest() const { return bci() + bytecode().get_offset_s2(raw_code()); } aoqi@0: int dest_w() const { return bci() + bytecode().get_offset_s4(raw_code()); } aoqi@0: aoqi@0: // One-byte indices. aoqi@0: int get_index_u1() const { assert_raw_index_size(1); return *(jubyte*)(bcp()+1); } aoqi@0: aoqi@0: protected: aoqi@0: void assert_raw_index_size(int size) const NOT_DEBUG_RETURN; aoqi@0: void assert_raw_stream(bool want_raw) const NOT_DEBUG_RETURN; aoqi@0: }; aoqi@0: aoqi@0: class RawBytecodeStream: public BaseBytecodeStream { aoqi@0: public: aoqi@0: // Construction aoqi@0: RawBytecodeStream(methodHandle method) : BaseBytecodeStream(method) { aoqi@0: _is_raw = true; aoqi@0: } aoqi@0: aoqi@0: public: aoqi@0: // Iteration aoqi@0: // Use raw_next() rather than next() for faster method reference aoqi@0: Bytecodes::Code raw_next() { aoqi@0: Bytecodes::Code code; aoqi@0: // set reading position aoqi@0: _bci = _next_bci; aoqi@0: assert(!is_last_bytecode(), "caller should check is_last_bytecode()"); aoqi@0: aoqi@0: address bcp = this->bcp(); aoqi@0: code = Bytecodes::code_or_bp_at(bcp); aoqi@0: aoqi@0: // set next bytecode position aoqi@0: int l = Bytecodes::length_for(code); aoqi@0: if (l > 0 && (_bci + l) <= _end_bci) { aoqi@0: assert(code != Bytecodes::_wide && code != Bytecodes::_tableswitch aoqi@0: && code != Bytecodes::_lookupswitch, "can't be special bytecode"); aoqi@0: _is_wide = false; aoqi@0: _next_bci += l; aoqi@0: _raw_code = code; aoqi@0: return code; aoqi@0: } else { aoqi@0: return raw_next_special(code); aoqi@0: } aoqi@0: } aoqi@0: Bytecodes::Code raw_next_special(Bytecodes::Code code); aoqi@0: aoqi@0: // Unsigned indices, widening, with no swapping of bytes aoqi@0: int get_index() const { return (is_wide()) ? get_index_u2_raw(bcp() + 2) : get_index_u1(); } aoqi@0: // Get an unsigned 2-byte index, with no swapping of bytes. aoqi@0: int get_index_u2() const { assert(!is_wide(), ""); return get_index_u2_raw(bcp() + 1); } aoqi@0: aoqi@0: private: aoqi@0: int get_index_u2_raw(address p) const { aoqi@0: assert_raw_index_size(2); assert_raw_stream(true); aoqi@0: return Bytes::get_Java_u2(p); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: // In BytecodeStream, non-java bytecodes will be translated into the aoqi@0: // corresponding java bytecodes. aoqi@0: aoqi@0: class BytecodeStream: public BaseBytecodeStream { aoqi@0: Bytecodes::Code _code; aoqi@0: aoqi@0: public: aoqi@0: // Construction aoqi@0: BytecodeStream(methodHandle method) : BaseBytecodeStream(method) { } aoqi@0: aoqi@0: // Iteration aoqi@0: Bytecodes::Code next() { aoqi@0: Bytecodes::Code raw_code, code; aoqi@0: // set reading position aoqi@0: _bci = _next_bci; aoqi@0: if (is_last_bytecode()) { aoqi@0: // indicate end of bytecode stream aoqi@0: raw_code = code = Bytecodes::_illegal; aoqi@0: } else { aoqi@0: // get bytecode aoqi@0: address bcp = this->bcp(); aoqi@0: raw_code = Bytecodes::code_at(_method(), bcp); aoqi@0: code = Bytecodes::java_code(raw_code); aoqi@0: // set next bytecode position aoqi@0: // aoqi@0: // note that we cannot advance before having the aoqi@0: // tty bytecode otherwise the stepping is wrong! aoqi@0: // (carefull: length_for(...) must be used first!) aoqi@0: int l = Bytecodes::length_for(code); aoqi@0: if (l == 0) l = Bytecodes::length_at(_method(), bcp); aoqi@0: _next_bci += l; aoqi@0: assert(_bci < _next_bci, "length must be > 0"); aoqi@0: // set attributes aoqi@0: _is_wide = false; aoqi@0: // check for special (uncommon) cases aoqi@0: if (code == Bytecodes::_wide) { aoqi@0: raw_code = (Bytecodes::Code)bcp[1]; aoqi@0: code = raw_code; // wide BCs are always Java-normal aoqi@0: _is_wide = true; aoqi@0: } aoqi@0: assert(Bytecodes::is_java_code(code), "sanity check"); aoqi@0: } aoqi@0: _raw_code = raw_code; aoqi@0: _code = code; aoqi@0: return _code; aoqi@0: } aoqi@0: aoqi@0: bool is_active_breakpoint() const { return Bytecodes::is_active_breakpoint_at(bcp()); } aoqi@0: Bytecodes::Code code() const { return _code; } aoqi@0: aoqi@0: // Unsigned indices, widening aoqi@0: int get_index() const { return is_wide() ? bytecode().get_index_u2(raw_code(), true) : get_index_u1(); } aoqi@0: // Get an unsigned 2-byte index, swapping the bytes if necessary. aoqi@0: int get_index_u2() const { assert_raw_stream(false); aoqi@0: return bytecode().get_index_u2(raw_code(), false); } aoqi@0: // Get an unsigned 2-byte index in native order. aoqi@0: int get_index_u2_cpcache() const { assert_raw_stream(false); aoqi@0: return bytecode().get_index_u2_cpcache(raw_code()); } aoqi@0: int get_index_u4() const { assert_raw_stream(false); aoqi@0: return bytecode().get_index_u4(raw_code()); } aoqi@0: bool has_index_u4() const { return bytecode().has_index_u4(raw_code()); } aoqi@0: }; aoqi@0: aoqi@0: #endif // SHARE_VM_INTERPRETER_BYTECODESTREAM_HPP