Mercurial > hg > truffle
diff src/share/vm/ci/ciStreams.hpp @ 0:a61af66fc99e jdk7-b24
Initial load
author | duke |
---|---|
date | Sat, 01 Dec 2007 00:00:00 +0000 |
parents | |
children | be93aad57795 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/ci/ciStreams.hpp Sat Dec 01 00:00:00 2007 +0000 @@ -0,0 +1,369 @@ +/* + * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +// ciBytecodeStream +// +// The class is used to iterate over the bytecodes of a method. +// It hides the details of constant pool structure/access by +// providing accessors for constant pool items. It returns only pure +// Java bytecodes; VM-internal _fast bytecodes are translated back to +// their original form during iteration. +class ciBytecodeStream : StackObj { +private: + // Handling for the weird bytecodes + Bytecodes::Code wide(); // Handle wide bytecode + Bytecodes::Code table(Bytecodes::Code); // Handle complicated inline table + + static Bytecodes::Code check_java(Bytecodes::Code c) { + assert(Bytecodes::is_java_code(c), "should not return _fast bytecodes"); + return c; + } + + ciMethod* _method; // the method + ciInstanceKlass* _holder; + address _bc_start; // Start of current bytecode for table + address _was_wide; // Address past last wide bytecode + jint* _table_base; // Aligned start of last table or switch + + address _start; // Start of bytecodes + address _end; // Past end of bytecodes + address _pc; // Current PC + Bytecodes::Code _bc; // Current bytecode + + void reset( address base, unsigned int size ) { + _bc_start =_was_wide = 0; + _start = _pc = base; _end = base + size; } + +public: + // End-Of-Bytecodes + static Bytecodes::Code EOBC() { + return Bytecodes::_illegal; + } + + ciBytecodeStream(ciMethod* m) { + reset_to_method(m); + } + + ciBytecodeStream() { + reset_to_method(NULL); + } + + ciMethod* method() const { return _method; } + + void reset_to_method(ciMethod* m) { + _method = m; + if (m == NULL) { + _holder = NULL; + reset(NULL, 0); + } else { + _holder = m->holder(); + reset(m->code(), m->code_size()); + } + } + + void reset_to_bci( int bci ); + + // Force the iterator to report a certain bci. + void force_bci(int bci); + + void set_max_bci( int max ) { + _end = _start + max; + } + + address cur_bcp() { return _bc_start; } // Returns bcp to current instruction + int next_bci() const { return _pc -_start; } + int cur_bci() const { return _bc_start - _start; } + + Bytecodes::Code cur_bc() const{ return check_java(_bc); } + Bytecodes::Code next_bc() { return Bytecodes::java_code((Bytecodes::Code)* _pc); } + + // Return current ByteCode and increment PC to next bytecode, skipping all + // intermediate constants. Returns EOBC at end. + // Expected usage: + // while( (bc = iter.next()) != EOBC() ) { ... } + Bytecodes::Code next() { + _bc_start = _pc; // Capture start of bc + if( _pc >= _end ) return EOBC(); // End-Of-Bytecodes + + // Fetch Java bytecode + // All rewritten bytecodes maintain the size of original bytecode. + _bc = Bytecodes::java_code((Bytecodes::Code)*_pc); + int csize = Bytecodes::length_for(_bc); // Expected size + + if( _bc == Bytecodes::_wide ) { + _bc=wide(); // Handle wide bytecode + } else if( csize == 0 ) { + _bc=table(_bc); // Handle inline tables + } else { + _pc += csize; // Bump PC past bytecode + } + return check_java(_bc); + } + + bool is_wide() { return ( _pc == _was_wide ); } + + // Get a byte index following this bytecode. + // If prefixed with a wide bytecode, get a wide index. + int get_index() const { + return (_pc == _was_wide) // was widened? + ? Bytes::get_Java_u2(_bc_start+2) // yes, return wide index + : _bc_start[1]; // no, return narrow index + } + + // Set a byte index following this bytecode. + // If prefixed with a wide bytecode, get a wide index. + void put_index(int idx) { + if (_pc == _was_wide) // was widened? + Bytes::put_Java_u2(_bc_start+2,idx); // yes, set wide index + else + _bc_start[1]=idx; // no, set narrow index + } + + // Get 2-byte index (getfield/putstatic/etc) + int get_index_big() const { return Bytes::get_Java_u2(_bc_start+1); } + + // Get dimensions byte (multinewarray) + int get_dimensions() const { return *(unsigned char*)(_pc-1); } + + // Get unsigned index fast + int get_index_fast() const { return Bytes::get_native_u2(_pc-2); } + + // Sign-extended index byte/short, no widening + int get_byte() const { return (int8_t)(_pc[-1]); } + int get_short() const { return (int16_t)Bytes::get_Java_u2(_pc-2); } + int get_long() const { return (int32_t)Bytes::get_Java_u4(_pc-4); } + + // Get a byte signed constant for "iinc". Invalid for other bytecodes. + // If prefixed with a wide bytecode, get a wide constant + int get_iinc_con() const {return (_pc==_was_wide) ? get_short() :get_byte();} + + // 2-byte branch offset from current pc + int get_dest( ) const { + assert( Bytecodes::length_at(_bc_start) == sizeof(jshort)+1, "get_dest called with bad bytecode" ); + return _bc_start-_start + (short)Bytes::get_Java_u2(_pc-2); + } + + // 2-byte branch offset from next pc + int next_get_dest( ) const { + address next_bc_start = _pc; + assert( _pc < _end, "" ); + Bytecodes::Code next_bc = (Bytecodes::Code)*_pc; + assert( next_bc != Bytecodes::_wide, ""); + int next_csize = Bytecodes::length_for(next_bc); + assert( next_csize != 0, "" ); + assert( next_bc <= Bytecodes::_jsr_w, ""); + address next_pc = _pc + next_csize; + assert( Bytecodes::length_at(next_bc_start) == sizeof(jshort)+1, "next_get_dest called with bad bytecode" ); + return next_bc_start-_start + (short)Bytes::get_Java_u2(next_pc-2); + } + + // 4-byte branch offset from current pc + int get_far_dest( ) const { + assert( Bytecodes::length_at(_bc_start) == sizeof(jint)+1, "dest4 called with bad bytecode" ); + return _bc_start-_start + (int)Bytes::get_Java_u4(_pc-4); + } + + // For a lookup or switch table, return target destination + int get_int_table( int index ) const { + return Bytes::get_Java_u4((address)&_table_base[index]); } + + // For tableswitch - get length of offset part + int get_tableswitch_length() { return get_int_table(2)-get_int_table(1)+1; } + + int get_dest_table( int index ) const { + return cur_bci() + get_int_table(index); } + + // --- Constant pool access --- + int get_constant_index() const; + int get_field_index(); + int get_method_index(); + + // If this bytecode is a new, newarray, multianewarray, instanceof, + // or checkcast, get the referenced klass. + ciKlass* get_klass(bool& will_link); + int get_klass_index() const; + + // If this bytecode is one of the ldc variants, get the referenced + // constant + ciConstant get_constant(); + // True if the ldc variant points to an unresolved string + bool is_unresolved_string() const; + // True if the ldc variant points to an unresolved klass + bool is_unresolved_klass() const; + + // If this bytecode is one of get_field, get_static, put_field, + // or put_static, get the referenced field. + ciField* get_field(bool& will_link); + + ciInstanceKlass* get_declared_field_holder(); + int get_field_holder_index(); + int get_field_signature_index(); + + // If this is a method invocation bytecode, get the invoked method. + ciMethod* get_method(bool& will_link); + ciKlass* get_declared_method_holder(); + int get_method_holder_index(); + int get_method_signature_index(); +}; + + +// ciSignatureStream +// +// The class is used to iterate over the elements of a method signature. +class ciSignatureStream : public StackObj { +private: + ciSignature* _sig; + int _pos; +public: + ciSignatureStream(ciSignature* signature) { + _sig = signature; + _pos = 0; + } + + bool at_return_type() { return _pos == _sig->count(); } + + bool is_done() { return _pos > _sig->count(); } + + void next() { + if (_pos <= _sig->count()) { + _pos++; + } + } + + ciType* type() { + if (at_return_type()) { + return _sig->return_type(); + } else { + return _sig->type_at(_pos); + } + } +}; + + +// ciExceptionHandlerStream +// +// The class is used to iterate over the exception handlers of +// a method. +class ciExceptionHandlerStream : public StackObj { +private: + // The method whose handlers we are traversing + ciMethod* _method; + + // Our current position in the list of handlers + int _pos; + int _end; + + ciInstanceKlass* _exception_klass; + int _bci; + bool _is_exact; + +public: + ciExceptionHandlerStream(ciMethod* method) { + _method = method; + + // Force loading of method code and handlers. + _method->code(); + + _pos = 0; + _end = _method->_handler_count; + _exception_klass = NULL; + _bci = -1; + _is_exact = false; + } + + ciExceptionHandlerStream(ciMethod* method, int bci, + ciInstanceKlass* exception_klass = NULL, + bool is_exact = false) { + _method = method; + + // Force loading of method code and handlers. + _method->code(); + + _pos = -1; + _end = _method->_handler_count + 1; // include the rethrow handler + _exception_klass = (exception_klass != NULL && exception_klass->is_loaded() + ? exception_klass + : NULL); + _bci = bci; + assert(_bci >= 0, "bci out of range"); + _is_exact = is_exact; + next(); + } + + // These methods are currently implemented in an odd way. + // Count the number of handlers the iterator has ever produced + // or will ever produce. Do not include the final rethrow handler. + // That is, a trivial exception handler stream will have a count + // of zero and produce just the rethrow handler. + int count(); + + // Count the number of handlers this stream will produce from now on. + // Include the current handler, and the final rethrow handler. + // The remaining count will be zero iff is_done() is true, + int count_remaining(); + + bool is_done() { + return (_pos >= _end); + } + + void next() { + _pos++; + if (_bci != -1) { + // We are not iterating over all handlers... + while (!is_done()) { + ciExceptionHandler* handler = _method->_exception_handlers[_pos]; + if (handler->is_in_range(_bci)) { + if (handler->is_catch_all()) { + // Found final active catch block. + _end = _pos+1; + return; + } else if (_exception_klass == NULL || !handler->catch_klass()->is_loaded()) { + // We cannot do any type analysis here. Must conservatively assume + // catch block is reachable. + return; + } else if (_exception_klass->is_subtype_of(handler->catch_klass())) { + // This catch clause will definitely catch the exception. + // Final candidate. + _end = _pos+1; + return; + } else if (!_is_exact && + handler->catch_klass()->is_subtype_of(_exception_klass)) { + // This catch block may be reachable. + return; + } + } + + // The catch block was not pertinent. Go on. + _pos++; + } + } else { + // This is an iteration over all handlers. + return; + } + } + + ciExceptionHandler* handler() { + return _method->_exception_handlers[_pos]; + } +};