duke@435: /* coleenp@4037: * Copyright (c) 1999, 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_CI_CISTREAMS_HPP stefank@2314: #define SHARE_VM_CI_CISTREAMS_HPP stefank@2314: stefank@2314: #include "ci/ciClassList.hpp" stefank@2314: #include "ci/ciExceptionHandler.hpp" stefank@2314: #include "ci/ciInstanceKlass.hpp" stefank@2314: #include "ci/ciMethod.hpp" stefank@2314: #include "interpreter/bytecode.hpp" stefank@2314: duke@435: // ciBytecodeStream duke@435: // duke@435: // The class is used to iterate over the bytecodes of a method. duke@435: // It hides the details of constant pool structure/access by duke@435: // providing accessors for constant pool items. It returns only pure duke@435: // Java bytecodes; VM-internal _fast bytecodes are translated back to duke@435: // their original form during iteration. duke@435: class ciBytecodeStream : StackObj { duke@435: private: jrose@1920: // Handling for the weird bytecodes jrose@1920: Bytecodes::Code next_wide_or_table(Bytecodes::Code); // Handle _wide & complicated inline table duke@435: duke@435: static Bytecodes::Code check_java(Bytecodes::Code c) { duke@435: assert(Bytecodes::is_java_code(c), "should not return _fast bytecodes"); duke@435: return c; duke@435: } duke@435: jrose@1920: static Bytecodes::Code check_defined(Bytecodes::Code c) { jrose@1920: assert(Bytecodes::is_defined(c), ""); jrose@1920: return c; jrose@1920: } jrose@1920: duke@435: ciMethod* _method; // the method duke@435: ciInstanceKlass* _holder; duke@435: address _bc_start; // Start of current bytecode for table duke@435: address _was_wide; // Address past last wide bytecode duke@435: jint* _table_base; // Aligned start of last table or switch duke@435: duke@435: address _start; // Start of bytecodes duke@435: address _end; // Past end of bytecodes duke@435: address _pc; // Current PC duke@435: Bytecodes::Code _bc; // Current bytecode jrose@1920: Bytecodes::Code _raw_bc; // Current bytecode, raw form duke@435: duke@435: void reset( address base, unsigned int size ) { duke@435: _bc_start =_was_wide = 0; jrose@1957: _start = _pc = base; _end = base + size; jrose@1957: } duke@435: jrose@1920: void assert_wide(bool require_wide) const { jrose@1920: if (require_wide) jrose@1920: { assert(is_wide(), "must be a wide instruction"); } jrose@1920: else { assert(!is_wide(), "must not be a wide instruction"); } jrose@1920: } jrose@1920: never@2462: Bytecode bytecode() const { return Bytecode(this, _bc_start); } never@2462: Bytecode next_bytecode() const { return Bytecode(this, _pc); } jrose@1920: duke@435: public: duke@435: // End-Of-Bytecodes duke@435: static Bytecodes::Code EOBC() { duke@435: return Bytecodes::_illegal; duke@435: } duke@435: duke@435: ciBytecodeStream(ciMethod* m) { duke@435: reset_to_method(m); duke@435: } duke@435: duke@435: ciBytecodeStream() { duke@435: reset_to_method(NULL); duke@435: } duke@435: duke@435: ciMethod* method() const { return _method; } duke@435: duke@435: void reset_to_method(ciMethod* m) { duke@435: _method = m; duke@435: if (m == NULL) { duke@435: _holder = NULL; duke@435: reset(NULL, 0); duke@435: } else { duke@435: _holder = m->holder(); duke@435: reset(m->code(), m->code_size()); duke@435: } duke@435: } duke@435: duke@435: void reset_to_bci( int bci ); duke@435: duke@435: // Force the iterator to report a certain bci. duke@435: void force_bci(int bci); duke@435: duke@435: void set_max_bci( int max ) { duke@435: _end = _start + max; duke@435: } duke@435: jrose@1161: address cur_bcp() const { return _bc_start; } // Returns bcp to current instruction jrose@1920: int next_bci() const { return _pc - _start; } duke@435: int cur_bci() const { return _bc_start - _start; } jrose@1161: int instruction_size() const { return _pc - _bc_start; } duke@435: duke@435: Bytecodes::Code cur_bc() const{ return check_java(_bc); } jrose@1920: Bytecodes::Code cur_bc_raw() const { return check_defined(_raw_bc); } duke@435: Bytecodes::Code next_bc() { return Bytecodes::java_code((Bytecodes::Code)* _pc); } duke@435: duke@435: // Return current ByteCode and increment PC to next bytecode, skipping all duke@435: // intermediate constants. Returns EOBC at end. duke@435: // Expected usage: twisti@3097: // ciBytecodeStream iter(m); twisti@3097: // while (iter.next() != ciBytecodeStream::EOBC()) { ... } duke@435: Bytecodes::Code next() { duke@435: _bc_start = _pc; // Capture start of bc duke@435: if( _pc >= _end ) return EOBC(); // End-Of-Bytecodes duke@435: duke@435: // Fetch Java bytecode duke@435: // All rewritten bytecodes maintain the size of original bytecode. jrose@1920: _bc = Bytecodes::java_code(_raw_bc = (Bytecodes::Code)*_pc); duke@435: int csize = Bytecodes::length_for(_bc); // Expected size jrose@1920: _pc += csize; // Bump PC past bytecode jrose@1920: if (csize == 0) { jrose@1920: _bc = next_wide_or_table(_bc); duke@435: } duke@435: return check_java(_bc); duke@435: } duke@435: jrose@1161: bool is_wide() const { return ( _pc == _was_wide ); } duke@435: jrose@1920: // Does this instruction contain an index which refes into the CP cache? jrose@1957: bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); } jrose@1920: twisti@4021: bool has_optional_appendix() { return Bytecodes::has_optional_appendix(cur_bc_raw()); } twisti@4021: jrose@1920: int get_index_u1() const { never@2462: return bytecode().get_index_u1(cur_bc_raw()); jrose@1920: } jrose@1920: jrose@1957: int get_index_u1_cpcache() const { never@2462: return bytecode().get_index_u1_cpcache(cur_bc_raw()); jrose@1957: } jrose@1957: duke@435: // Get a byte index following this bytecode. duke@435: // If prefixed with a wide bytecode, get a wide index. duke@435: int get_index() const { jrose@1957: assert(!has_cache_index(), "else use cpcache variant"); duke@435: return (_pc == _was_wide) // was widened? jrose@1920: ? get_index_u2(true) // yes, return wide index jrose@1920: : get_index_u1(); // no, return narrow index duke@435: } duke@435: jrose@1920: // Get 2-byte index (byte swapping depending on which bytecode) jrose@1920: int get_index_u2(bool is_wide = false) const { never@2462: return bytecode().get_index_u2(cur_bc_raw(), is_wide); duke@435: } duke@435: jrose@1920: // Get 2-byte index in native byte order. (Rewriter::rewrite makes these.) jrose@1920: int get_index_u2_cpcache() const { never@2462: return bytecode().get_index_u2_cpcache(cur_bc_raw()); jrose@1161: } jrose@1161: jrose@1161: // Get 4-byte index, for invokedynamic. jrose@1920: int get_index_u4() const { never@2462: return bytecode().get_index_u4(cur_bc_raw()); jrose@1161: } jrose@1161: jrose@1920: bool has_index_u4() const { never@2462: return bytecode().has_index_u4(cur_bc_raw()); jrose@1920: } duke@435: duke@435: // Get dimensions byte (multinewarray) duke@435: int get_dimensions() const { return *(unsigned char*)(_pc-1); } duke@435: duke@435: // Sign-extended index byte/short, no widening never@2462: int get_constant_u1() const { return bytecode().get_constant_u1(instruction_size()-1, cur_bc_raw()); } never@2462: int get_constant_u2(bool is_wide = false) const { return bytecode().get_constant_u2(instruction_size()-2, cur_bc_raw(), is_wide); } duke@435: duke@435: // Get a byte signed constant for "iinc". Invalid for other bytecodes. duke@435: // If prefixed with a wide bytecode, get a wide constant jrose@1920: int get_iinc_con() const {return (_pc==_was_wide) ? (jshort) get_constant_u2(true) : (jbyte) get_constant_u1();} duke@435: duke@435: // 2-byte branch offset from current pc jrose@1920: int get_dest() const { never@2462: return cur_bci() + bytecode().get_offset_s2(cur_bc_raw()); duke@435: } duke@435: duke@435: // 2-byte branch offset from next pc jrose@1920: int next_get_dest() const { jrose@1920: assert(_pc < _end, ""); never@2462: return next_bci() + next_bytecode().get_offset_s2(Bytecodes::_ifeq); duke@435: } duke@435: duke@435: // 4-byte branch offset from current pc jrose@1920: int get_far_dest() const { never@2462: return cur_bci() + bytecode().get_offset_s4(cur_bc_raw()); duke@435: } duke@435: duke@435: // For a lookup or switch table, return target destination duke@435: int get_int_table( int index ) const { duke@435: return Bytes::get_Java_u4((address)&_table_base[index]); } duke@435: duke@435: // For tableswitch - get length of offset part duke@435: int get_tableswitch_length() { return get_int_table(2)-get_int_table(1)+1; } duke@435: duke@435: int get_dest_table( int index ) const { duke@435: return cur_bci() + get_int_table(index); } duke@435: duke@435: // --- Constant pool access --- jrose@1957: int get_constant_raw_index() const; jrose@1957: int get_constant_pool_index() const; jrose@1957: int get_constant_cache_index() const; duke@435: int get_field_index(); duke@435: int get_method_index(); duke@435: duke@435: // If this bytecode is a new, newarray, multianewarray, instanceof, duke@435: // or checkcast, get the referenced klass. duke@435: ciKlass* get_klass(bool& will_link); duke@435: int get_klass_index() const; duke@435: duke@435: // If this bytecode is one of the ldc variants, get the referenced jrose@1957: // constant. Do not attempt to resolve it, since that would require jrose@1957: // execution of Java code. If it is not resolved, return an unloaded jrose@1957: // object (ciConstant.as_object()->is_loaded() == false). duke@435: ciConstant get_constant(); jrose@1957: constantTag get_constant_pool_tag(int index) const; jrose@1957: jrose@1957: // True if the klass-using bytecode points to an unresolved klass jrose@1957: bool is_unresolved_klass() const { jrose@1957: constantTag tag = get_constant_pool_tag(get_klass_index()); jrose@1957: return tag.is_unresolved_klass(); jrose@1957: } duke@435: duke@435: // If this bytecode is one of get_field, get_static, put_field, duke@435: // or put_static, get the referenced field. duke@435: ciField* get_field(bool& will_link); duke@435: duke@435: ciInstanceKlass* get_declared_field_holder(); duke@435: int get_field_holder_index(); duke@435: int get_field_signature_index(); duke@435: twisti@4133: ciMethod* get_method(bool& will_link, ciSignature* *declared_signature_result); twisti@4133: bool has_appendix(); twisti@4133: ciObject* get_appendix(); twisti@4133: bool has_method_type(); twisti@4133: ciMethodType* get_method_type(); twisti@4133: ciKlass* get_declared_method_holder(); twisti@4133: int get_method_holder_index(); twisti@4133: int get_method_signature_index(); jrose@1161: coleenp@4037: // Get the resolved references arrays from the constant pool coleenp@4037: ciObjArray* get_resolved_references(); duke@435: }; duke@435: duke@435: duke@435: // ciSignatureStream duke@435: // duke@435: // The class is used to iterate over the elements of a method signature. duke@435: class ciSignatureStream : public StackObj { duke@435: private: duke@435: ciSignature* _sig; roland@5914: int _pos; roland@5914: // holder is a method's holder roland@5914: ciKlass* _holder; duke@435: public: roland@5914: ciSignatureStream(ciSignature* signature, ciKlass* holder = NULL) { duke@435: _sig = signature; duke@435: _pos = 0; roland@5914: _holder = holder; duke@435: } duke@435: duke@435: bool at_return_type() { return _pos == _sig->count(); } duke@435: duke@435: bool is_done() { return _pos > _sig->count(); } duke@435: duke@435: void next() { duke@435: if (_pos <= _sig->count()) { duke@435: _pos++; duke@435: } duke@435: } duke@435: duke@435: ciType* type() { duke@435: if (at_return_type()) { duke@435: return _sig->return_type(); duke@435: } else { duke@435: return _sig->type_at(_pos); duke@435: } duke@435: } roland@5914: roland@5914: // next klass in the signature roland@5914: ciKlass* next_klass() { roland@5914: ciKlass* sig_k; roland@5914: if (_holder != NULL) { roland@5914: sig_k = _holder; roland@5914: _holder = NULL; roland@5914: } else { roland@5914: while (!type()->is_klass()) { roland@5914: next(); roland@5914: } roland@5914: assert(!at_return_type(), "passed end of signature"); roland@5914: sig_k = type()->as_klass(); roland@5914: next(); roland@5914: } roland@5914: return sig_k; roland@5914: } duke@435: }; duke@435: duke@435: duke@435: // ciExceptionHandlerStream duke@435: // duke@435: // The class is used to iterate over the exception handlers of duke@435: // a method. duke@435: class ciExceptionHandlerStream : public StackObj { duke@435: private: duke@435: // The method whose handlers we are traversing duke@435: ciMethod* _method; duke@435: duke@435: // Our current position in the list of handlers duke@435: int _pos; duke@435: int _end; duke@435: duke@435: ciInstanceKlass* _exception_klass; duke@435: int _bci; duke@435: bool _is_exact; duke@435: duke@435: public: duke@435: ciExceptionHandlerStream(ciMethod* method) { duke@435: _method = method; duke@435: duke@435: // Force loading of method code and handlers. duke@435: _method->code(); duke@435: duke@435: _pos = 0; duke@435: _end = _method->_handler_count; duke@435: _exception_klass = NULL; duke@435: _bci = -1; duke@435: _is_exact = false; duke@435: } duke@435: duke@435: ciExceptionHandlerStream(ciMethod* method, int bci, duke@435: ciInstanceKlass* exception_klass = NULL, duke@435: bool is_exact = false) { duke@435: _method = method; duke@435: duke@435: // Force loading of method code and handlers. duke@435: _method->code(); duke@435: duke@435: _pos = -1; duke@435: _end = _method->_handler_count + 1; // include the rethrow handler duke@435: _exception_klass = (exception_klass != NULL && exception_klass->is_loaded() duke@435: ? exception_klass duke@435: : NULL); duke@435: _bci = bci; duke@435: assert(_bci >= 0, "bci out of range"); duke@435: _is_exact = is_exact; duke@435: next(); duke@435: } duke@435: duke@435: // These methods are currently implemented in an odd way. duke@435: // Count the number of handlers the iterator has ever produced duke@435: // or will ever produce. Do not include the final rethrow handler. duke@435: // That is, a trivial exception handler stream will have a count duke@435: // of zero and produce just the rethrow handler. duke@435: int count(); duke@435: duke@435: // Count the number of handlers this stream will produce from now on. duke@435: // Include the current handler, and the final rethrow handler. duke@435: // The remaining count will be zero iff is_done() is true, duke@435: int count_remaining(); duke@435: duke@435: bool is_done() { duke@435: return (_pos >= _end); duke@435: } duke@435: duke@435: void next() { duke@435: _pos++; duke@435: if (_bci != -1) { duke@435: // We are not iterating over all handlers... duke@435: while (!is_done()) { duke@435: ciExceptionHandler* handler = _method->_exception_handlers[_pos]; duke@435: if (handler->is_in_range(_bci)) { duke@435: if (handler->is_catch_all()) { duke@435: // Found final active catch block. duke@435: _end = _pos+1; duke@435: return; duke@435: } else if (_exception_klass == NULL || !handler->catch_klass()->is_loaded()) { duke@435: // We cannot do any type analysis here. Must conservatively assume duke@435: // catch block is reachable. duke@435: return; duke@435: } else if (_exception_klass->is_subtype_of(handler->catch_klass())) { duke@435: // This catch clause will definitely catch the exception. duke@435: // Final candidate. duke@435: _end = _pos+1; duke@435: return; duke@435: } else if (!_is_exact && duke@435: handler->catch_klass()->is_subtype_of(_exception_klass)) { duke@435: // This catch block may be reachable. duke@435: return; duke@435: } duke@435: } duke@435: duke@435: // The catch block was not pertinent. Go on. duke@435: _pos++; duke@435: } duke@435: } else { duke@435: // This is an iteration over all handlers. duke@435: return; duke@435: } duke@435: } duke@435: duke@435: ciExceptionHandler* handler() { duke@435: return _method->_exception_handlers[_pos]; duke@435: } duke@435: }; stefank@2314: never@2462: never@2462: never@2462: // Implementation for declarations in bytecode.hpp never@2462: Bytecode::Bytecode(const ciBytecodeStream* stream, address bcp): _bcp(bcp != NULL ? bcp : stream->cur_bcp()), _code(Bytecodes::code_at(NULL, addr_at(0))) {} never@2462: Bytecode_lookupswitch::Bytecode_lookupswitch(const ciBytecodeStream* stream): Bytecode(stream) { verify(); } never@2462: Bytecode_tableswitch::Bytecode_tableswitch(const ciBytecodeStream* stream): Bytecode(stream) { verify(); } never@2462: stefank@2314: #endif // SHARE_VM_CI_CISTREAMS_HPP