2007-12-01 00:00:00 +00:00
/*
2010-05-27 19:08:38 -07:00
* Copyright ( c ) 1999 , 2010 , Oracle and / or its affiliates . All rights reserved .
2007-12-01 00:00:00 +00:00
* 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 .
*
2010-05-27 19:08:38 -07:00
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
2007-12-01 00:00:00 +00:00
*
*/
2010-11-23 13:22:55 -08:00
# include "precompiled.hpp"
# include "c1/c1_Compilation.hpp"
# include "c1/c1_FrameMap.hpp"
# include "c1/c1_GraphBuilder.hpp"
# include "c1/c1_IR.hpp"
# include "c1/c1_InstructionPrinter.hpp"
# include "c1/c1_Optimizer.hpp"
# include "utilities/bitMap.inline.hpp"
2007-12-01 00:00:00 +00:00
// Implementation of XHandlers
//
// Note: This code could eventually go away if we are
// just using the ciExceptionHandlerStream.
XHandlers : : XHandlers ( ciMethod * method ) : _list ( method - > exception_table_length ( ) ) {
ciExceptionHandlerStream s ( method ) ;
while ( ! s . is_done ( ) ) {
_list . append ( new XHandler ( s . handler ( ) ) ) ;
s . next ( ) ;
}
assert ( s . count ( ) = = method - > exception_table_length ( ) , " exception table lengths inconsistent " ) ;
}
// deep copy of all XHandler contained in list
XHandlers : : XHandlers ( XHandlers * other ) :
_list ( other - > length ( ) )
{
for ( int i = 0 ; i < other - > length ( ) ; i + + ) {
_list . append ( new XHandler ( other - > handler_at ( i ) ) ) ;
}
}
// Returns whether a particular exception type can be caught. Also
// returns true if klass is unloaded or any exception handler
// classes are unloaded. type_is_exact indicates whether the throw
// is known to be exactly that class or it might throw a subtype.
bool XHandlers : : could_catch ( ciInstanceKlass * klass , bool type_is_exact ) const {
// the type is unknown so be conservative
if ( ! klass - > is_loaded ( ) ) {
return true ;
}
for ( int i = 0 ; i < length ( ) ; i + + ) {
XHandler * handler = handler_at ( i ) ;
if ( handler - > is_catch_all ( ) ) {
// catch of ANY
return true ;
}
ciInstanceKlass * handler_klass = handler - > catch_klass ( ) ;
// if it's unknown it might be catchable
if ( ! handler_klass - > is_loaded ( ) ) {
return true ;
}
// if the throw type is definitely a subtype of the catch type
// then it can be caught.
if ( klass - > is_subtype_of ( handler_klass ) ) {
return true ;
}
if ( ! type_is_exact ) {
// If the type isn't exactly known then it can also be caught by
// catch statements where the inexact type is a subtype of the
// catch type.
// given: foo extends bar extends Exception
// throw bar can be caught by catch foo, catch bar, and catch
// Exception, however it can't be caught by any handlers without
// bar in its type hierarchy.
if ( handler_klass - > is_subtype_of ( klass ) ) {
return true ;
}
}
}
return false ;
}
bool XHandlers : : equals ( XHandlers * others ) const {
if ( others = = NULL ) return false ;
if ( length ( ) ! = others - > length ( ) ) return false ;
for ( int i = 0 ; i < length ( ) ; i + + ) {
if ( ! handler_at ( i ) - > equals ( others - > handler_at ( i ) ) ) return false ;
}
return true ;
}
bool XHandler : : equals ( XHandler * other ) const {
assert ( entry_pco ( ) ! = - 1 & & other - > entry_pco ( ) ! = - 1 , " must have entry_pco " ) ;
if ( entry_pco ( ) ! = other - > entry_pco ( ) ) return false ;
if ( scope_count ( ) ! = other - > scope_count ( ) ) return false ;
if ( _desc ! = other - > _desc ) return false ;
assert ( entry_block ( ) = = other - > entry_block ( ) , " entry_block must be equal when entry_pco is equal " ) ;
return true ;
}
// Implementation of IRScope
BlockBegin * IRScope : : build_graph ( Compilation * compilation , int osr_bci ) {
GraphBuilder gm ( compilation , this ) ;
NOT_PRODUCT ( if ( PrintValueNumbering & & Verbose ) gm . print_stats ( ) ) ;
if ( compilation - > bailed_out ( ) ) return NULL ;
return gm . start ( ) ;
}
IRScope : : IRScope ( Compilation * compilation , IRScope * caller , int caller_bci , ciMethod * method , int osr_bci , bool create_graph )
: _callees ( 2 )
, _compilation ( compilation )
, _requires_phi_function ( method - > max_locals ( ) )
{
_caller = caller ;
_level = caller = = NULL ? 0 : caller - > level ( ) + 1 ;
_method = method ;
_xhandlers = new XHandlers ( method ) ;
_number_of_locks = 0 ;
_monitor_pairing_ok = method - > has_balanced_monitors ( ) ;
_start = NULL ;
if ( osr_bci = = - 1 ) {
_requires_phi_function . clear ( ) ;
} else {
// selective creation of phi functions is not possibel in osr-methods
_requires_phi_function . set_range ( 0 , method - > max_locals ( ) ) ;
}
assert ( method - > holder ( ) - > is_loaded ( ) , " method holder must be loaded " ) ;
// build graph if monitor pairing is ok
if ( create_graph & & monitor_pairing_ok ( ) ) _start = build_graph ( compilation , osr_bci ) ;
}
int IRScope : : max_stack ( ) const {
int my_max = method ( ) - > max_stack ( ) ;
int callee_max = 0 ;
for ( int i = 0 ; i < number_of_callees ( ) ; i + + ) {
callee_max = MAX2 ( callee_max , callee_no ( i ) - > max_stack ( ) ) ;
}
return my_max + callee_max ;
}
2009-07-31 17:12:33 -07:00
bool IRScopeDebugInfo : : should_reexecute ( ) {
ciMethod * cur_method = scope ( ) - > method ( ) ;
int cur_bci = bci ( ) ;
if ( cur_method ! = NULL & & cur_bci ! = SynchronizationEntryBCI ) {
Bytecodes : : Code code = cur_method - > java_code_at_bci ( cur_bci ) ;
return Interpreter : : bytecode_should_reexecute ( code ) ;
} else
return false ;
}
2007-12-01 00:00:00 +00:00
// Implementation of CodeEmitInfo
// Stack must be NON-null
2009-12-29 19:08:54 +01:00
CodeEmitInfo : : CodeEmitInfo ( ValueStack * stack , XHandlers * exception_handlers )
2007-12-01 00:00:00 +00:00
: _scope ( stack - > scope ( ) )
, _scope_debug_info ( NULL )
, _oop_map ( NULL )
, _stack ( stack )
, _exception_handlers ( exception_handlers )
2010-05-21 02:59:24 -07:00
, _is_method_handle_invoke ( false ) {
2007-12-01 00:00:00 +00:00
assert ( _stack ! = NULL , " must be non null " ) ;
}
2009-12-29 19:08:54 +01:00
CodeEmitInfo : : CodeEmitInfo ( CodeEmitInfo * info , ValueStack * stack )
2007-12-01 00:00:00 +00:00
: _scope ( info - > _scope )
, _exception_handlers ( NULL )
, _scope_debug_info ( NULL )
2010-05-21 02:59:24 -07:00
, _oop_map ( NULL )
2009-12-29 19:08:54 +01:00
, _stack ( stack = = NULL ? info - > _stack : stack )
2010-05-21 02:59:24 -07:00
, _is_method_handle_invoke ( info - > _is_method_handle_invoke ) {
2007-12-01 00:00:00 +00:00
// deep copy of exception handlers
if ( info - > _exception_handlers ! = NULL ) {
_exception_handlers = new XHandlers ( info - > _exception_handlers ) ;
}
}
2010-05-21 02:59:24 -07:00
void CodeEmitInfo : : record_debug_info ( DebugInformationRecorder * recorder , int pc_offset ) {
2007-12-01 00:00:00 +00:00
// record the safepoint before recording the debug info for enclosing scopes
recorder - > add_safepoint ( pc_offset , _oop_map - > deep_copy ( ) ) ;
2010-05-21 02:59:24 -07:00
_scope_debug_info - > record_debug_info ( recorder , pc_offset , true /*topmost*/ , _is_method_handle_invoke ) ;
2007-12-01 00:00:00 +00:00
recorder - > end_safepoint ( pc_offset ) ;
}
void CodeEmitInfo : : add_register_oop ( LIR_Opr opr ) {
assert ( _oop_map ! = NULL , " oop map must already exist " ) ;
assert ( opr - > is_single_cpu ( ) , " should not call otherwise " ) ;
VMReg name = frame_map ( ) - > regname ( opr ) ;
_oop_map - > set_oop ( name ) ;
}
// Implementation of IR
IR : : IR ( Compilation * compilation , ciMethod * method , int osr_bci ) :
_locals_size ( in_WordSize ( - 1 ) )
, _num_loops ( 0 ) {
// setup IR fields
_compilation = compilation ;
_top_scope = new IRScope ( compilation , NULL , - 1 , method , osr_bci , true ) ;
_code = NULL ;
}
void IR : : optimize ( ) {
Optimizer opt ( this ) ;
2010-09-03 17:51:07 -07:00
if ( ! compilation ( ) - > profile_branches ( ) ) {
if ( DoCEE ) {
opt . eliminate_conditional_expressions ( ) ;
2007-12-01 00:00:00 +00:00
# ifndef PRODUCT
2010-09-03 17:51:07 -07:00
if ( PrintCFG | | PrintCFG1 ) { tty - > print_cr ( " CFG after CEE " ) ; print ( true ) ; }
if ( PrintIR | | PrintIR1 ) { tty - > print_cr ( " IR after CEE " ) ; print ( false ) ; }
2007-12-01 00:00:00 +00:00
# endif
2010-09-03 17:51:07 -07:00
}
if ( EliminateBlocks ) {
opt . eliminate_blocks ( ) ;
2007-12-01 00:00:00 +00:00
# ifndef PRODUCT
2010-09-03 17:51:07 -07:00
if ( PrintCFG | | PrintCFG1 ) { tty - > print_cr ( " CFG after block elimination " ) ; print ( true ) ; }
if ( PrintIR | | PrintIR1 ) { tty - > print_cr ( " IR after block elimination " ) ; print ( false ) ; }
2007-12-01 00:00:00 +00:00
# endif
2010-09-03 17:51:07 -07:00
}
2007-12-01 00:00:00 +00:00
}
if ( EliminateNullChecks ) {
opt . eliminate_null_checks ( ) ;
# ifndef PRODUCT
if ( PrintCFG | | PrintCFG1 ) { tty - > print_cr ( " CFG after null check elimination " ) ; print ( true ) ; }
if ( PrintIR | | PrintIR1 ) { tty - > print_cr ( " IR after null check elimination " ) ; print ( false ) ; }
# endif
}
}
static int sort_pairs ( BlockPair * * a , BlockPair * * b ) {
if ( ( * a ) - > from ( ) = = ( * b ) - > from ( ) ) {
return ( * a ) - > to ( ) - > block_id ( ) - ( * b ) - > to ( ) - > block_id ( ) ;
} else {
return ( * a ) - > from ( ) - > block_id ( ) - ( * b ) - > from ( ) - > block_id ( ) ;
}
}
class CriticalEdgeFinder : public BlockClosure {
BlockPairList blocks ;
IR * _ir ;
public :
CriticalEdgeFinder ( IR * ir ) : _ir ( ir ) { }
void block_do ( BlockBegin * bb ) {
BlockEnd * be = bb - > end ( ) ;
int nos = be - > number_of_sux ( ) ;
if ( nos > = 2 ) {
for ( int i = 0 ; i < nos ; i + + ) {
BlockBegin * sux = be - > sux_at ( i ) ;
if ( sux - > number_of_preds ( ) > = 2 ) {
blocks . append ( new BlockPair ( bb , sux ) ) ;
}
}
}
}
void split_edges ( ) {
BlockPair * last_pair = NULL ;
blocks . sort ( sort_pairs ) ;
for ( int i = 0 ; i < blocks . length ( ) ; i + + ) {
BlockPair * pair = blocks . at ( i ) ;
if ( last_pair ! = NULL & & pair - > is_same ( last_pair ) ) continue ;
BlockBegin * from = pair - > from ( ) ;
BlockBegin * to = pair - > to ( ) ;
BlockBegin * split = from - > insert_block_between ( to ) ;
# ifndef PRODUCT
if ( ( PrintIR | | PrintIR1 ) & & Verbose ) {
tty - > print_cr ( " Split critical edge B%d -> B%d (new block B%d) " ,
from - > block_id ( ) , to - > block_id ( ) , split - > block_id ( ) ) ;
}
# endif
last_pair = pair ;
}
}
} ;
void IR : : split_critical_edges ( ) {
CriticalEdgeFinder cef ( this ) ;
iterate_preorder ( & cef ) ;
cef . split_edges ( ) ;
}
2010-06-04 11:18:04 -07:00
class UseCountComputer : public ValueVisitor , BlockClosure {
2007-12-01 00:00:00 +00:00
private :
2010-06-04 11:18:04 -07:00
void visit ( Value * n ) {
2007-12-01 00:00:00 +00:00
// Local instructions and Phis for expression stack values at the
// start of basic blocks are not added to the instruction list
2010-10-15 09:38:20 +02:00
if ( ! ( * n ) - > is_linked ( ) & & ( * n ) - > can_be_linked ( ) ) {
2007-12-01 00:00:00 +00:00
assert ( false , " a node was not appended to the graph " ) ;
2010-06-04 11:18:04 -07:00
Compilation : : current ( ) - > bailout ( " a node was not appended to the graph " ) ;
2007-12-01 00:00:00 +00:00
}
// use n's input if not visited before
if ( ! ( * n ) - > is_pinned ( ) & & ! ( * n ) - > has_uses ( ) ) {
// note: a) if the instruction is pinned, it will be handled by compute_use_count
// b) if the instruction has uses, it was touched before
// => in both cases we don't need to update n's values
uses_do ( n ) ;
}
// use n
( * n ) - > _use_count + + ;
}
2010-06-04 11:18:04 -07:00
Values * worklist ;
int depth ;
2007-12-01 00:00:00 +00:00
enum {
max_recurse_depth = 20
} ;
2010-06-04 11:18:04 -07:00
void uses_do ( Value * n ) {
2007-12-01 00:00:00 +00:00
depth + + ;
if ( depth > max_recurse_depth ) {
// don't allow the traversal to recurse too deeply
worklist - > push ( * n ) ;
} else {
2010-06-04 11:18:04 -07:00
( * n ) - > input_values_do ( this ) ;
2007-12-01 00:00:00 +00:00
// special handling for some instructions
if ( ( * n ) - > as_BlockEnd ( ) ! = NULL ) {
// note on BlockEnd:
// must 'use' the stack only if the method doesn't
// terminate, however, in those cases stack is empty
2010-06-04 11:18:04 -07:00
( * n ) - > state_values_do ( this ) ;
2007-12-01 00:00:00 +00:00
}
}
depth - - ;
}
2010-06-04 11:18:04 -07:00
void block_do ( BlockBegin * b ) {
2007-12-01 00:00:00 +00:00
depth = 0 ;
// process all pinned nodes as the roots of expression trees
for ( Instruction * n = b ; n ! = NULL ; n = n - > next ( ) ) {
if ( n - > is_pinned ( ) ) uses_do ( & n ) ;
}
assert ( depth = = 0 , " should have counted back down " ) ;
// now process any unpinned nodes which recursed too deeply
while ( worklist - > length ( ) > 0 ) {
Value t = worklist - > pop ( ) ;
if ( ! t - > is_pinned ( ) ) {
// compute the use count
uses_do ( & t ) ;
// pin the instruction so that LIRGenerator doesn't recurse
// too deeply during it's evaluation.
t - > pin ( ) ;
}
}
assert ( depth = = 0 , " should have counted back down " ) ;
}
2010-06-04 11:18:04 -07:00
UseCountComputer ( ) {
worklist = new Values ( ) ;
depth = 0 ;
}
2007-12-01 00:00:00 +00:00
public :
static void compute ( BlockList * blocks ) {
2010-06-04 11:18:04 -07:00
UseCountComputer ucc ;
blocks - > iterate_backward ( & ucc ) ;
2007-12-01 00:00:00 +00:00
}
} ;
// helper macro for short definition of trace-output inside code
# ifndef PRODUCT
# define TRACE_LINEAR_SCAN(level, code) \
if ( TraceLinearScanLevel > = level ) { \
code ; \
}
# else
# define TRACE_LINEAR_SCAN(level, code)
# endif
class ComputeLinearScanOrder : public StackObj {
private :
int _max_block_id ; // the highest block_id of a block
int _num_blocks ; // total number of blocks (smaller than _max_block_id)
int _num_loops ; // total number of loops
bool _iterative_dominators ; // method requires iterative computation of dominatiors
BlockList * _linear_scan_order ; // the resulting list of blocks in correct order
BitMap _visited_blocks ; // used for recursive processing of blocks
BitMap _active_blocks ; // used for recursive processing of blocks
BitMap _dominator_blocks ; // temproary BitMap used for computation of dominator
intArray _forward_branches ; // number of incoming forward branches for each block
BlockList _loop_end_blocks ; // list of all loop end blocks collected during count_edges
BitMap2D _loop_map ; // two-dimensional bit set: a bit is set if a block is contained in a loop
BlockList _work_list ; // temporary list (used in mark_loops and compute_order)
2010-09-03 17:51:07 -07:00
Compilation * _compilation ;
2007-12-01 00:00:00 +00:00
// accessors for _visited_blocks and _active_blocks
void init_visited ( ) { _active_blocks . clear ( ) ; _visited_blocks . clear ( ) ; }
bool is_visited ( BlockBegin * b ) const { return _visited_blocks . at ( b - > block_id ( ) ) ; }
bool is_active ( BlockBegin * b ) const { return _active_blocks . at ( b - > block_id ( ) ) ; }
void set_visited ( BlockBegin * b ) { assert ( ! is_visited ( b ) , " already set " ) ; _visited_blocks . set_bit ( b - > block_id ( ) ) ; }
void set_active ( BlockBegin * b ) { assert ( ! is_active ( b ) , " already set " ) ; _active_blocks . set_bit ( b - > block_id ( ) ) ; }
void clear_active ( BlockBegin * b ) { assert ( is_active ( b ) , " not already " ) ; _active_blocks . clear_bit ( b - > block_id ( ) ) ; }
// accessors for _forward_branches
void inc_forward_branches ( BlockBegin * b ) { _forward_branches . at_put ( b - > block_id ( ) , _forward_branches . at ( b - > block_id ( ) ) + 1 ) ; }
int dec_forward_branches ( BlockBegin * b ) { _forward_branches . at_put ( b - > block_id ( ) , _forward_branches . at ( b - > block_id ( ) ) - 1 ) ; return _forward_branches . at ( b - > block_id ( ) ) ; }
// accessors for _loop_map
bool is_block_in_loop ( int loop_idx , BlockBegin * b ) const { return _loop_map . at ( loop_idx , b - > block_id ( ) ) ; }
void set_block_in_loop ( int loop_idx , BlockBegin * b ) { _loop_map . set_bit ( loop_idx , b - > block_id ( ) ) ; }
void clear_block_in_loop ( int loop_idx , int block_id ) { _loop_map . clear_bit ( loop_idx , block_id ) ; }
// count edges between blocks
void count_edges ( BlockBegin * cur , BlockBegin * parent ) ;
// loop detection
void mark_loops ( ) ;
void clear_non_natural_loops ( BlockBegin * start_block ) ;
void assign_loop_depth ( BlockBegin * start_block ) ;
// computation of final block order
BlockBegin * common_dominator ( BlockBegin * a , BlockBegin * b ) ;
void compute_dominator ( BlockBegin * cur , BlockBegin * parent ) ;
int compute_weight ( BlockBegin * cur ) ;
bool ready_for_processing ( BlockBegin * cur ) ;
void sort_into_work_list ( BlockBegin * b ) ;
void append_block ( BlockBegin * cur ) ;
void compute_order ( BlockBegin * start_block ) ;
// fixup of dominators for non-natural loops
bool compute_dominators_iter ( ) ;
void compute_dominators ( ) ;
// debug functions
NOT_PRODUCT ( void print_blocks ( ) ; )
DEBUG_ONLY ( void verify ( ) ; )
2010-09-03 17:51:07 -07:00
Compilation * compilation ( ) const { return _compilation ; }
2007-12-01 00:00:00 +00:00
public :
2010-09-03 17:51:07 -07:00
ComputeLinearScanOrder ( Compilation * c , BlockBegin * start_block ) ;
2007-12-01 00:00:00 +00:00
// accessors for final result
BlockList * linear_scan_order ( ) const { return _linear_scan_order ; }
int num_loops ( ) const { return _num_loops ; }
} ;
2010-09-03 17:51:07 -07:00
ComputeLinearScanOrder : : ComputeLinearScanOrder ( Compilation * c , BlockBegin * start_block ) :
2007-12-01 00:00:00 +00:00
_max_block_id ( BlockBegin : : number_of_blocks ( ) ) ,
_num_blocks ( 0 ) ,
_num_loops ( 0 ) ,
_iterative_dominators ( false ) ,
_visited_blocks ( _max_block_id ) ,
_active_blocks ( _max_block_id ) ,
_dominator_blocks ( _max_block_id ) ,
_forward_branches ( _max_block_id , 0 ) ,
_loop_end_blocks ( 8 ) ,
_work_list ( 8 ) ,
_linear_scan_order ( NULL ) , // initialized later with correct size
2010-09-03 17:51:07 -07:00
_loop_map ( 0 , 0 ) , // initialized later with correct size
_compilation ( c )
2007-12-01 00:00:00 +00:00
{
TRACE_LINEAR_SCAN ( 2 , " ***** computing linear-scan block order " ) ;
init_visited ( ) ;
count_edges ( start_block , NULL ) ;
2010-09-03 17:51:07 -07:00
if ( compilation ( ) - > is_profiling ( ) ) {
2010-12-02 17:21:12 -08:00
ciMethod * method = compilation ( ) - > method ( ) ;
if ( ! method - > is_accessor ( ) ) {
ciMethodData * md = method - > method_data_or_null ( ) ;
assert ( md ! = NULL , " Sanity " ) ;
md - > set_compilation_stats ( _num_loops , _num_blocks ) ;
}
2010-09-03 17:51:07 -07:00
}
2007-12-01 00:00:00 +00:00
if ( _num_loops > 0 ) {
mark_loops ( ) ;
clear_non_natural_loops ( start_block ) ;
assign_loop_depth ( start_block ) ;
}
compute_order ( start_block ) ;
compute_dominators ( ) ;
NOT_PRODUCT ( print_blocks ( ) ) ;
DEBUG_ONLY ( verify ( ) ) ;
}
// Traverse the CFG:
// * count total number of blocks
// * count all incoming edges and backward incoming edges
// * number loop header blocks
// * create a list with all loop end blocks
void ComputeLinearScanOrder : : count_edges ( BlockBegin * cur , BlockBegin * parent ) {
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " Enter count_edges for block B%d coming from B%d " , cur - > block_id ( ) , parent ! = NULL ? parent - > block_id ( ) : - 1 ) ) ;
assert ( cur - > dominator ( ) = = NULL , " dominator already initialized " ) ;
if ( is_active ( cur ) ) {
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " backward branch " ) ) ;
assert ( is_visited ( cur ) , " block must be visisted when block is active " ) ;
assert ( parent ! = NULL , " must have parent " ) ;
cur - > set ( BlockBegin : : linear_scan_loop_header_flag ) ;
cur - > set ( BlockBegin : : backward_branch_target_flag ) ;
parent - > set ( BlockBegin : : linear_scan_loop_end_flag ) ;
2008-11-11 23:03:35 -08:00
// When a loop header is also the start of an exception handler, then the backward branch is
// an exception edge. Because such edges are usually critical edges which cannot be split, the
// loop must be excluded here from processing.
if ( cur - > is_set ( BlockBegin : : exception_entry_flag ) ) {
// Make sure that dominators are correct in this weird situation
_iterative_dominators = true ;
return ;
}
assert ( parent - > number_of_sux ( ) = = 1 & & parent - > sux_at ( 0 ) = = cur ,
" loop end blocks must have one successor (critical edges are split) " ) ;
2007-12-01 00:00:00 +00:00
_loop_end_blocks . append ( parent ) ;
return ;
}
// increment number of incoming forward branches
inc_forward_branches ( cur ) ;
if ( is_visited ( cur ) ) {
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " block already visited " ) ) ;
return ;
}
_num_blocks + + ;
set_visited ( cur ) ;
set_active ( cur ) ;
// recursive call for all successors
int i ;
for ( i = cur - > number_of_sux ( ) - 1 ; i > = 0 ; i - - ) {
count_edges ( cur - > sux_at ( i ) , cur ) ;
}
for ( i = cur - > number_of_exception_handlers ( ) - 1 ; i > = 0 ; i - - ) {
count_edges ( cur - > exception_handler_at ( i ) , cur ) ;
}
clear_active ( cur ) ;
// Each loop has a unique number.
// When multiple loops are nested, assign_loop_depth assumes that the
// innermost loop has the lowest number. This is guaranteed by setting
// the loop number after the recursive calls for the successors above
// have returned.
if ( cur - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) ) {
assert ( cur - > loop_index ( ) = = - 1 , " cannot set loop-index twice " ) ;
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " Block B%d is loop header of loop %d " , cur - > block_id ( ) , _num_loops ) ) ;
cur - > set_loop_index ( _num_loops ) ;
_num_loops + + ;
}
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " Finished count_edges for block B%d " , cur - > block_id ( ) ) ) ;
}
void ComputeLinearScanOrder : : mark_loops ( ) {
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " ----- marking loops " ) ) ;
_loop_map = BitMap2D ( _num_loops , _max_block_id ) ;
_loop_map . clear ( ) ;
for ( int i = _loop_end_blocks . length ( ) - 1 ; i > = 0 ; i - - ) {
BlockBegin * loop_end = _loop_end_blocks . at ( i ) ;
BlockBegin * loop_start = loop_end - > sux_at ( 0 ) ;
int loop_idx = loop_start - > loop_index ( ) ;
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " Processing loop from B%d to B%d (loop %d): " , loop_start - > block_id ( ) , loop_end - > block_id ( ) , loop_idx ) ) ;
assert ( loop_end - > is_set ( BlockBegin : : linear_scan_loop_end_flag ) , " loop end flag must be set " ) ;
assert ( loop_end - > number_of_sux ( ) = = 1 , " incorrect number of successors " ) ;
assert ( loop_start - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) , " loop header flag must be set " ) ;
assert ( loop_idx > = 0 & & loop_idx < _num_loops , " loop index not set " ) ;
assert ( _work_list . is_empty ( ) , " work list must be empty before processing " ) ;
// add the end-block of the loop to the working list
_work_list . push ( loop_end ) ;
set_block_in_loop ( loop_idx , loop_end ) ;
do {
BlockBegin * cur = _work_list . pop ( ) ;
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " processing B%d " , cur - > block_id ( ) ) ) ;
assert ( is_block_in_loop ( loop_idx , cur ) , " bit in loop map must be set when block is in work list " ) ;
// recursive processing of all predecessors ends when start block of loop is reached
if ( cur ! = loop_start & & ! cur - > is_set ( BlockBegin : : osr_entry_flag ) ) {
for ( int j = cur - > number_of_preds ( ) - 1 ; j > = 0 ; j - - ) {
BlockBegin * pred = cur - > pred_at ( j ) ;
if ( ! is_block_in_loop ( loop_idx , pred ) /*&& !pred->is_set(BlockBeginosr_entry_flag)*/ ) {
// this predecessor has not been processed yet, so add it to work list
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " pushing B%d " , pred - > block_id ( ) ) ) ;
_work_list . push ( pred ) ;
set_block_in_loop ( loop_idx , pred ) ;
}
}
}
} while ( ! _work_list . is_empty ( ) ) ;
}
}
// check for non-natural loops (loops where the loop header does not dominate
// all other loop blocks = loops with mulitple entries).
// such loops are ignored
void ComputeLinearScanOrder : : clear_non_natural_loops ( BlockBegin * start_block ) {
for ( int i = _num_loops - 1 ; i > = 0 ; i - - ) {
if ( is_block_in_loop ( i , start_block ) ) {
// loop i contains the entry block of the method
// -> this is not a natural loop, so ignore it
TRACE_LINEAR_SCAN ( 2 , tty - > print_cr ( " Loop %d is non-natural, so it is ignored " , i ) ) ;
for ( int block_id = _max_block_id - 1 ; block_id > = 0 ; block_id - - ) {
clear_block_in_loop ( i , block_id ) ;
}
_iterative_dominators = true ;
}
}
}
void ComputeLinearScanOrder : : assign_loop_depth ( BlockBegin * start_block ) {
TRACE_LINEAR_SCAN ( 3 , " ----- computing loop-depth and weight " ) ;
init_visited ( ) ;
assert ( _work_list . is_empty ( ) , " work list must be empty before processing " ) ;
_work_list . append ( start_block ) ;
do {
BlockBegin * cur = _work_list . pop ( ) ;
if ( ! is_visited ( cur ) ) {
set_visited ( cur ) ;
TRACE_LINEAR_SCAN ( 4 , tty - > print_cr ( " Computing loop depth for block B%d " , cur - > block_id ( ) ) ) ;
// compute loop-depth and loop-index for the block
assert ( cur - > loop_depth ( ) = = 0 , " cannot set loop-depth twice " ) ;
int i ;
int loop_depth = 0 ;
int min_loop_idx = - 1 ;
for ( i = _num_loops - 1 ; i > = 0 ; i - - ) {
if ( is_block_in_loop ( i , cur ) ) {
loop_depth + + ;
min_loop_idx = i ;
}
}
cur - > set_loop_depth ( loop_depth ) ;
cur - > set_loop_index ( min_loop_idx ) ;
// append all unvisited successors to work list
for ( i = cur - > number_of_sux ( ) - 1 ; i > = 0 ; i - - ) {
_work_list . append ( cur - > sux_at ( i ) ) ;
}
for ( i = cur - > number_of_exception_handlers ( ) - 1 ; i > = 0 ; i - - ) {
_work_list . append ( cur - > exception_handler_at ( i ) ) ;
}
}
} while ( ! _work_list . is_empty ( ) ) ;
}
BlockBegin * ComputeLinearScanOrder : : common_dominator ( BlockBegin * a , BlockBegin * b ) {
assert ( a ! = NULL & & b ! = NULL , " must have input blocks " ) ;
_dominator_blocks . clear ( ) ;
while ( a ! = NULL ) {
_dominator_blocks . set_bit ( a - > block_id ( ) ) ;
assert ( a - > dominator ( ) ! = NULL | | a = = _linear_scan_order - > at ( 0 ) , " dominator must be initialized " ) ;
a = a - > dominator ( ) ;
}
while ( b ! = NULL & & ! _dominator_blocks . at ( b - > block_id ( ) ) ) {
assert ( b - > dominator ( ) ! = NULL | | b = = _linear_scan_order - > at ( 0 ) , " dominator must be initialized " ) ;
b = b - > dominator ( ) ;
}
assert ( b ! = NULL , " could not find dominator " ) ;
return b ;
}
void ComputeLinearScanOrder : : compute_dominator ( BlockBegin * cur , BlockBegin * parent ) {
if ( cur - > dominator ( ) = = NULL ) {
TRACE_LINEAR_SCAN ( 4 , tty - > print_cr ( " DOM: initializing dominator of B%d to B%d " , cur - > block_id ( ) , parent - > block_id ( ) ) ) ;
cur - > set_dominator ( parent ) ;
} else if ( ! ( cur - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) & & parent - > is_set ( BlockBegin : : linear_scan_loop_end_flag ) ) ) {
TRACE_LINEAR_SCAN ( 4 , tty - > print_cr ( " DOM: computing dominator of B%d: common dominator of B%d and B%d is B%d " , cur - > block_id ( ) , parent - > block_id ( ) , cur - > dominator ( ) - > block_id ( ) , common_dominator ( cur - > dominator ( ) , parent ) - > block_id ( ) ) ) ;
assert ( cur - > number_of_preds ( ) > 1 , " " ) ;
cur - > set_dominator ( common_dominator ( cur - > dominator ( ) , parent ) ) ;
}
}
int ComputeLinearScanOrder : : compute_weight ( BlockBegin * cur ) {
BlockBegin * single_sux = NULL ;
if ( cur - > number_of_sux ( ) = = 1 ) {
single_sux = cur - > sux_at ( 0 ) ;
}
// limit loop-depth to 15 bit (only for security reason, it will never be so big)
int weight = ( cur - > loop_depth ( ) & 0x7FFF ) < < 16 ;
// general macro for short definition of weight flags
// the first instance of INC_WEIGHT_IF has the highest priority
int cur_bit = 15 ;
# define INC_WEIGHT_IF(condition) if ((condition)) { weight |= (1 << cur_bit); } cur_bit--;
// this is necessery for the (very rare) case that two successing blocks have
// the same loop depth, but a different loop index (can happen for endless loops
// with exception handlers)
INC_WEIGHT_IF ( ! cur - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) ) ;
// loop end blocks (blocks that end with a backward branch) are added
// after all other blocks of the loop.
INC_WEIGHT_IF ( ! cur - > is_set ( BlockBegin : : linear_scan_loop_end_flag ) ) ;
// critical edge split blocks are prefered because than they have a bigger
// proability to be completely empty
INC_WEIGHT_IF ( cur - > is_set ( BlockBegin : : critical_edge_split_flag ) ) ;
// exceptions should not be thrown in normal control flow, so these blocks
// are added as late as possible
INC_WEIGHT_IF ( cur - > end ( ) - > as_Throw ( ) = = NULL & & ( single_sux = = NULL | | single_sux - > end ( ) - > as_Throw ( ) = = NULL ) ) ;
INC_WEIGHT_IF ( cur - > end ( ) - > as_Return ( ) = = NULL & & ( single_sux = = NULL | | single_sux - > end ( ) - > as_Return ( ) = = NULL ) ) ;
// exceptions handlers are added as late as possible
INC_WEIGHT_IF ( ! cur - > is_set ( BlockBegin : : exception_entry_flag ) ) ;
// guarantee that weight is > 0
weight | = 1 ;
# undef INC_WEIGHT_IF
assert ( cur_bit > = 0 , " too many flags " ) ;
assert ( weight > 0 , " weight cannot become negative " ) ;
return weight ;
}
bool ComputeLinearScanOrder : : ready_for_processing ( BlockBegin * cur ) {
// Discount the edge just traveled.
// When the number drops to zero, all forward branches were processed
if ( dec_forward_branches ( cur ) ! = 0 ) {
return false ;
}
assert ( _linear_scan_order - > index_of ( cur ) = = - 1 , " block already processed (block can be ready only once) " ) ;
assert ( _work_list . index_of ( cur ) = = - 1 , " block already in work-list (block can be ready only once) " ) ;
return true ;
}
void ComputeLinearScanOrder : : sort_into_work_list ( BlockBegin * cur ) {
assert ( _work_list . index_of ( cur ) = = - 1 , " block already in work list " ) ;
int cur_weight = compute_weight ( cur ) ;
// the linear_scan_number is used to cache the weight of a block
cur - > set_linear_scan_number ( cur_weight ) ;
# ifndef PRODUCT
if ( StressLinearScan ) {
_work_list . insert_before ( 0 , cur ) ;
return ;
}
# endif
_work_list . append ( NULL ) ; // provide space for new element
int insert_idx = _work_list . length ( ) - 1 ;
while ( insert_idx > 0 & & _work_list . at ( insert_idx - 1 ) - > linear_scan_number ( ) > cur_weight ) {
_work_list . at_put ( insert_idx , _work_list . at ( insert_idx - 1 ) ) ;
insert_idx - - ;
}
_work_list . at_put ( insert_idx , cur ) ;
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " Sorted B%d into worklist. new worklist: " , cur - > block_id ( ) ) ) ;
TRACE_LINEAR_SCAN ( 3 , for ( int i = 0 ; i < _work_list . length ( ) ; i + + ) tty - > print_cr ( " %8d B%2d weight:%6x " , i , _work_list . at ( i ) - > block_id ( ) , _work_list . at ( i ) - > linear_scan_number ( ) ) ) ;
# ifdef ASSERT
for ( int i = 0 ; i < _work_list . length ( ) ; i + + ) {
assert ( _work_list . at ( i ) - > linear_scan_number ( ) > 0 , " weight not set " ) ;
assert ( i = = 0 | | _work_list . at ( i - 1 ) - > linear_scan_number ( ) < = _work_list . at ( i ) - > linear_scan_number ( ) , " incorrect order in worklist " ) ;
}
# endif
}
void ComputeLinearScanOrder : : append_block ( BlockBegin * cur ) {
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " appending block B%d (weight 0x%6x) to linear-scan order " , cur - > block_id ( ) , cur - > linear_scan_number ( ) ) ) ;
assert ( _linear_scan_order - > index_of ( cur ) = = - 1 , " cannot add the same block twice " ) ;
// currently, the linear scan order and code emit order are equal.
// therefore the linear_scan_number and the weight of a block must also
// be equal.
cur - > set_linear_scan_number ( _linear_scan_order - > length ( ) ) ;
_linear_scan_order - > append ( cur ) ;
}
void ComputeLinearScanOrder : : compute_order ( BlockBegin * start_block ) {
TRACE_LINEAR_SCAN ( 3 , " ----- computing final block order " ) ;
// the start block is always the first block in the linear scan order
_linear_scan_order = new BlockList ( _num_blocks ) ;
append_block ( start_block ) ;
assert ( start_block - > end ( ) - > as_Base ( ) ! = NULL , " start block must end with Base-instruction " ) ;
BlockBegin * std_entry = ( ( Base * ) start_block - > end ( ) ) - > std_entry ( ) ;
BlockBegin * osr_entry = ( ( Base * ) start_block - > end ( ) ) - > osr_entry ( ) ;
BlockBegin * sux_of_osr_entry = NULL ;
if ( osr_entry ! = NULL ) {
// special handling for osr entry:
// ignore the edge between the osr entry and its successor for processing
// the osr entry block is added manually below
assert ( osr_entry - > number_of_sux ( ) = = 1 , " osr entry must have exactly one successor " ) ;
assert ( osr_entry - > sux_at ( 0 ) - > number_of_preds ( ) > = 2 , " sucessor of osr entry must have two predecessors (otherwise it is not present in normal control flow " ) ;
sux_of_osr_entry = osr_entry - > sux_at ( 0 ) ;
dec_forward_branches ( sux_of_osr_entry ) ;
compute_dominator ( osr_entry , start_block ) ;
_iterative_dominators = true ;
}
compute_dominator ( std_entry , start_block ) ;
// start processing with standard entry block
assert ( _work_list . is_empty ( ) , " list must be empty before processing " ) ;
if ( ready_for_processing ( std_entry ) ) {
sort_into_work_list ( std_entry ) ;
} else {
assert ( false , " the std_entry must be ready for processing (otherwise, the method has no start block) " ) ;
}
do {
BlockBegin * cur = _work_list . pop ( ) ;
if ( cur = = sux_of_osr_entry ) {
// the osr entry block is ignored in normal processing, it is never added to the
// work list. Instead, it is added as late as possible manually here.
append_block ( osr_entry ) ;
compute_dominator ( cur , osr_entry ) ;
}
append_block ( cur ) ;
int i ;
int num_sux = cur - > number_of_sux ( ) ;
// changed loop order to get "intuitive" order of if- and else-blocks
for ( i = 0 ; i < num_sux ; i + + ) {
BlockBegin * sux = cur - > sux_at ( i ) ;
compute_dominator ( sux , cur ) ;
if ( ready_for_processing ( sux ) ) {
sort_into_work_list ( sux ) ;
}
}
num_sux = cur - > number_of_exception_handlers ( ) ;
for ( i = 0 ; i < num_sux ; i + + ) {
BlockBegin * sux = cur - > exception_handler_at ( i ) ;
compute_dominator ( sux , cur ) ;
if ( ready_for_processing ( sux ) ) {
sort_into_work_list ( sux ) ;
}
}
} while ( _work_list . length ( ) > 0 ) ;
}
bool ComputeLinearScanOrder : : compute_dominators_iter ( ) {
bool changed = false ;
int num_blocks = _linear_scan_order - > length ( ) ;
assert ( _linear_scan_order - > at ( 0 ) - > dominator ( ) = = NULL , " must not have dominator " ) ;
assert ( _linear_scan_order - > at ( 0 ) - > number_of_preds ( ) = = 0 , " must not have predecessors " ) ;
for ( int i = 1 ; i < num_blocks ; i + + ) {
BlockBegin * block = _linear_scan_order - > at ( i ) ;
BlockBegin * dominator = block - > pred_at ( 0 ) ;
int num_preds = block - > number_of_preds ( ) ;
for ( int i = 1 ; i < num_preds ; i + + ) {
dominator = common_dominator ( dominator , block - > pred_at ( i ) ) ;
}
if ( dominator ! = block - > dominator ( ) ) {
TRACE_LINEAR_SCAN ( 4 , tty - > print_cr ( " DOM: updating dominator of B%d from B%d to B%d " , block - > block_id ( ) , block - > dominator ( ) - > block_id ( ) , dominator - > block_id ( ) ) ) ;
block - > set_dominator ( dominator ) ;
changed = true ;
}
}
return changed ;
}
void ComputeLinearScanOrder : : compute_dominators ( ) {
TRACE_LINEAR_SCAN ( 3 , tty - > print_cr ( " ----- computing dominators (iterative computation reqired: %d) " , _iterative_dominators ) ) ;
// iterative computation of dominators is only required for methods with non-natural loops
// and OSR-methods. For all other methods, the dominators computed when generating the
// linear scan block order are correct.
if ( _iterative_dominators ) {
do {
TRACE_LINEAR_SCAN ( 1 , tty - > print_cr ( " DOM: next iteration of fix-point calculation " ) ) ;
} while ( compute_dominators_iter ( ) ) ;
}
// check that dominators are correct
assert ( ! compute_dominators_iter ( ) , " fix point not reached " ) ;
}
# ifndef PRODUCT
void ComputeLinearScanOrder : : print_blocks ( ) {
if ( TraceLinearScanLevel > = 2 ) {
tty - > print_cr ( " ----- loop information: " ) ;
for ( int block_idx = 0 ; block_idx < _linear_scan_order - > length ( ) ; block_idx + + ) {
BlockBegin * cur = _linear_scan_order - > at ( block_idx ) ;
tty - > print ( " %4d: B%2d: " , cur - > linear_scan_number ( ) , cur - > block_id ( ) ) ;
for ( int loop_idx = 0 ; loop_idx < _num_loops ; loop_idx + + ) {
tty - > print ( " %d " , is_block_in_loop ( loop_idx , cur ) ) ;
}
tty - > print_cr ( " -> loop_index: %2d, loop_depth: %2d " , cur - > loop_index ( ) , cur - > loop_depth ( ) ) ;
}
}
if ( TraceLinearScanLevel > = 1 ) {
tty - > print_cr ( " ----- linear-scan block order: " ) ;
for ( int block_idx = 0 ; block_idx < _linear_scan_order - > length ( ) ; block_idx + + ) {
BlockBegin * cur = _linear_scan_order - > at ( block_idx ) ;
tty - > print ( " %4d: B%2d loop: %2d depth: %2d " , cur - > linear_scan_number ( ) , cur - > block_id ( ) , cur - > loop_index ( ) , cur - > loop_depth ( ) ) ;
tty - > print ( cur - > is_set ( BlockBegin : : exception_entry_flag ) ? " ex " : " " ) ;
tty - > print ( cur - > is_set ( BlockBegin : : critical_edge_split_flag ) ? " ce " : " " ) ;
tty - > print ( cur - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) ? " lh " : " " ) ;
tty - > print ( cur - > is_set ( BlockBegin : : linear_scan_loop_end_flag ) ? " le " : " " ) ;
if ( cur - > dominator ( ) ! = NULL ) {
tty - > print ( " dom: B%d " , cur - > dominator ( ) - > block_id ( ) ) ;
} else {
tty - > print ( " dom: NULL " ) ;
}
if ( cur - > number_of_preds ( ) > 0 ) {
tty - > print ( " preds: " ) ;
for ( int j = 0 ; j < cur - > number_of_preds ( ) ; j + + ) {
BlockBegin * pred = cur - > pred_at ( j ) ;
tty - > print ( " B%d " , pred - > block_id ( ) ) ;
}
}
if ( cur - > number_of_sux ( ) > 0 ) {
tty - > print ( " sux: " ) ;
for ( int j = 0 ; j < cur - > number_of_sux ( ) ; j + + ) {
BlockBegin * sux = cur - > sux_at ( j ) ;
tty - > print ( " B%d " , sux - > block_id ( ) ) ;
}
}
if ( cur - > number_of_exception_handlers ( ) > 0 ) {
tty - > print ( " ex: " ) ;
for ( int j = 0 ; j < cur - > number_of_exception_handlers ( ) ; j + + ) {
BlockBegin * ex = cur - > exception_handler_at ( j ) ;
tty - > print ( " B%d " , ex - > block_id ( ) ) ;
}
}
tty - > cr ( ) ;
}
}
}
# endif
# ifdef ASSERT
void ComputeLinearScanOrder : : verify ( ) {
assert ( _linear_scan_order - > length ( ) = = _num_blocks , " wrong number of blocks in list " ) ;
if ( StressLinearScan ) {
// blocks are scrambled when StressLinearScan is used
return ;
}
// check that all successors of a block have a higher linear-scan-number
// and that all predecessors of a block have a lower linear-scan-number
// (only backward branches of loops are ignored)
int i ;
for ( i = 0 ; i < _linear_scan_order - > length ( ) ; i + + ) {
BlockBegin * cur = _linear_scan_order - > at ( i ) ;
assert ( cur - > linear_scan_number ( ) = = i , " incorrect linear_scan_number " ) ;
assert ( cur - > linear_scan_number ( ) > = 0 & & cur - > linear_scan_number ( ) = = _linear_scan_order - > index_of ( cur ) , " incorrect linear_scan_number " ) ;
int j ;
for ( j = cur - > number_of_sux ( ) - 1 ; j > = 0 ; j - - ) {
BlockBegin * sux = cur - > sux_at ( j ) ;
assert ( sux - > linear_scan_number ( ) > = 0 & & sux - > linear_scan_number ( ) = = _linear_scan_order - > index_of ( sux ) , " incorrect linear_scan_number " ) ;
if ( ! cur - > is_set ( BlockBegin : : linear_scan_loop_end_flag ) ) {
assert ( cur - > linear_scan_number ( ) < sux - > linear_scan_number ( ) , " invalid order " ) ;
}
if ( cur - > loop_depth ( ) = = sux - > loop_depth ( ) ) {
assert ( cur - > loop_index ( ) = = sux - > loop_index ( ) | | sux - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) , " successing blocks with same loop depth must have same loop index " ) ;
}
}
for ( j = cur - > number_of_preds ( ) - 1 ; j > = 0 ; j - - ) {
BlockBegin * pred = cur - > pred_at ( j ) ;
assert ( pred - > linear_scan_number ( ) > = 0 & & pred - > linear_scan_number ( ) = = _linear_scan_order - > index_of ( pred ) , " incorrect linear_scan_number " ) ;
if ( ! cur - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) ) {
assert ( cur - > linear_scan_number ( ) > pred - > linear_scan_number ( ) , " invalid order " ) ;
}
if ( cur - > loop_depth ( ) = = pred - > loop_depth ( ) ) {
assert ( cur - > loop_index ( ) = = pred - > loop_index ( ) | | cur - > is_set ( BlockBegin : : linear_scan_loop_header_flag ) , " successing blocks with same loop depth must have same loop index " ) ;
}
assert ( cur - > dominator ( ) - > linear_scan_number ( ) < = cur - > pred_at ( j ) - > linear_scan_number ( ) , " dominator must be before predecessors " ) ;
}
// check dominator
if ( i = = 0 ) {
assert ( cur - > dominator ( ) = = NULL , " first block has no dominator " ) ;
} else {
assert ( cur - > dominator ( ) ! = NULL , " all but first block must have dominator " ) ;
}
assert ( cur - > number_of_preds ( ) ! = 1 | | cur - > dominator ( ) = = cur - > pred_at ( 0 ) , " Single predecessor must also be dominator " ) ;
}
// check that all loops are continuous
for ( int loop_idx = 0 ; loop_idx < _num_loops ; loop_idx + + ) {
int block_idx = 0 ;
assert ( ! is_block_in_loop ( loop_idx , _linear_scan_order - > at ( block_idx ) ) , " the first block must not be present in any loop " ) ;
// skip blocks before the loop
while ( block_idx < _num_blocks & & ! is_block_in_loop ( loop_idx , _linear_scan_order - > at ( block_idx ) ) ) {
block_idx + + ;
}
// skip blocks of loop
while ( block_idx < _num_blocks & & is_block_in_loop ( loop_idx , _linear_scan_order - > at ( block_idx ) ) ) {
block_idx + + ;
}
// after the first non-loop block, there must not be another loop-block
while ( block_idx < _num_blocks ) {
assert ( ! is_block_in_loop ( loop_idx , _linear_scan_order - > at ( block_idx ) ) , " loop not continuous in linear-scan order " ) ;
block_idx + + ;
}
}
}
# endif
void IR : : compute_code ( ) {
assert ( is_valid ( ) , " IR must be valid " ) ;
2010-09-03 17:51:07 -07:00
ComputeLinearScanOrder compute_order ( compilation ( ) , start ( ) ) ;
2007-12-01 00:00:00 +00:00
_num_loops = compute_order . num_loops ( ) ;
_code = compute_order . linear_scan_order ( ) ;
}
void IR : : compute_use_counts ( ) {
// make sure all values coming out of this block get evaluated.
int num_blocks = _code - > length ( ) ;
for ( int i = 0 ; i < num_blocks ; i + + ) {
_code - > at ( i ) - > end ( ) - > state ( ) - > pin_stack_for_linear_scan ( ) ;
}
// compute use counts
UseCountComputer : : compute ( _code ) ;
}
void IR : : iterate_preorder ( BlockClosure * closure ) {
assert ( is_valid ( ) , " IR must be valid " ) ;
start ( ) - > iterate_preorder ( closure ) ;
}
void IR : : iterate_postorder ( BlockClosure * closure ) {
assert ( is_valid ( ) , " IR must be valid " ) ;
start ( ) - > iterate_postorder ( closure ) ;
}
void IR : : iterate_linear_scan_order ( BlockClosure * closure ) {
linear_scan_order ( ) - > iterate_forward ( closure ) ;
}
# ifndef PRODUCT
class BlockPrinter : public BlockClosure {
private :
InstructionPrinter * _ip ;
bool _cfg_only ;
bool _live_only ;
public :
BlockPrinter ( InstructionPrinter * ip , bool cfg_only , bool live_only = false ) {
_ip = ip ;
_cfg_only = cfg_only ;
_live_only = live_only ;
}
virtual void block_do ( BlockBegin * block ) {
if ( _cfg_only ) {
_ip - > print_instr ( block ) ; tty - > cr ( ) ;
} else {
block - > print_block ( * _ip , _live_only ) ;
}
}
} ;
void IR : : print ( BlockBegin * start , bool cfg_only , bool live_only ) {
ttyLocker ttyl ;
InstructionPrinter ip ( ! cfg_only ) ;
BlockPrinter bp ( & ip , cfg_only , live_only ) ;
start - > iterate_preorder ( & bp ) ;
tty - > cr ( ) ;
}
void IR : : print ( bool cfg_only , bool live_only ) {
if ( is_valid ( ) ) {
print ( start ( ) , cfg_only , live_only ) ;
} else {
tty - > print_cr ( " invalid IR " ) ;
}
}
define_array ( BlockListArray , BlockList * )
define_stack ( BlockListList , BlockListArray )
class PredecessorValidator : public BlockClosure {
private :
BlockListList * _predecessors ;
BlockList * _blocks ;
static int cmp ( BlockBegin * * a , BlockBegin * * b ) {
return ( * a ) - > block_id ( ) - ( * b ) - > block_id ( ) ;
}
public :
PredecessorValidator ( IR * hir ) {
ResourceMark rm ;
_predecessors = new BlockListList ( BlockBegin : : number_of_blocks ( ) , NULL ) ;
_blocks = new BlockList ( ) ;
int i ;
hir - > start ( ) - > iterate_preorder ( this ) ;
if ( hir - > code ( ) ! = NULL ) {
assert ( hir - > code ( ) - > length ( ) = = _blocks - > length ( ) , " must match " ) ;
for ( i = 0 ; i < _blocks - > length ( ) ; i + + ) {
assert ( hir - > code ( ) - > contains ( _blocks - > at ( i ) ) , " should be in both lists " ) ;
}
}
for ( i = 0 ; i < _blocks - > length ( ) ; i + + ) {
BlockBegin * block = _blocks - > at ( i ) ;
BlockList * preds = _predecessors - > at ( block - > block_id ( ) ) ;
if ( preds = = NULL ) {
assert ( block - > number_of_preds ( ) = = 0 , " should be the same " ) ;
continue ;
}
// clone the pred list so we can mutate it
BlockList * pred_copy = new BlockList ( ) ;
int j ;
for ( j = 0 ; j < block - > number_of_preds ( ) ; j + + ) {
pred_copy - > append ( block - > pred_at ( j ) ) ;
}
// sort them in the same order
preds - > sort ( cmp ) ;
pred_copy - > sort ( cmp ) ;
int length = MIN2 ( preds - > length ( ) , block - > number_of_preds ( ) ) ;
for ( j = 0 ; j < block - > number_of_preds ( ) ; j + + ) {
assert ( preds - > at ( j ) = = pred_copy - > at ( j ) , " must match " ) ;
}
assert ( preds - > length ( ) = = block - > number_of_preds ( ) , " should be the same " ) ;
}
}
virtual void block_do ( BlockBegin * block ) {
_blocks - > append ( block ) ;
BlockEnd * be = block - > end ( ) ;
int n = be - > number_of_sux ( ) ;
int i ;
for ( i = 0 ; i < n ; i + + ) {
BlockBegin * sux = be - > sux_at ( i ) ;
assert ( ! sux - > is_set ( BlockBegin : : exception_entry_flag ) , " must not be xhandler " ) ;
BlockList * preds = _predecessors - > at_grow ( sux - > block_id ( ) , NULL ) ;
if ( preds = = NULL ) {
preds = new BlockList ( ) ;
_predecessors - > at_put ( sux - > block_id ( ) , preds ) ;
}
preds - > append ( block ) ;
}
n = block - > number_of_exception_handlers ( ) ;
for ( i = 0 ; i < n ; i + + ) {
BlockBegin * sux = block - > exception_handler_at ( i ) ;
assert ( sux - > is_set ( BlockBegin : : exception_entry_flag ) , " must be xhandler " ) ;
BlockList * preds = _predecessors - > at_grow ( sux - > block_id ( ) , NULL ) ;
if ( preds = = NULL ) {
preds = new BlockList ( ) ;
_predecessors - > at_put ( sux - > block_id ( ) , preds ) ;
}
preds - > append ( block ) ;
}
}
} ;
void IR : : verify ( ) {
# ifdef ASSERT
PredecessorValidator pv ( this ) ;
# endif
}
# endif // PRODUCT
2010-06-04 11:18:04 -07:00
void SubstitutionResolver : : visit ( Value * v ) {
2007-12-01 00:00:00 +00:00
Value v0 = * v ;
if ( v0 ) {
Value vs = v0 - > subst ( ) ;
if ( vs ! = v0 ) {
* v = v0 - > subst ( ) ;
}
}
}
# ifdef ASSERT
2010-06-04 11:18:04 -07:00
class SubstitutionChecker : public ValueVisitor {
void visit ( Value * v ) {
Value v0 = * v ;
if ( v0 ) {
Value vs = v0 - > subst ( ) ;
assert ( vs = = v0 , " missed substitution " ) ;
}
2007-12-01 00:00:00 +00:00
}
2010-06-04 11:18:04 -07:00
} ;
2007-12-01 00:00:00 +00:00
# endif
void SubstitutionResolver : : block_do ( BlockBegin * block ) {
Instruction * last = NULL ;
for ( Instruction * n = block ; n ! = NULL ; ) {
2010-06-04 11:18:04 -07:00
n - > values_do ( this ) ;
2007-12-01 00:00:00 +00:00
// need to remove this instruction from the instruction stream
if ( n - > subst ( ) ! = n ) {
assert ( last ! = NULL , " must have last " ) ;
2009-12-29 19:08:54 +01:00
last - > set_next ( n - > next ( ) ) ;
2007-12-01 00:00:00 +00:00
} else {
last = n ;
}
n = last - > next ( ) ;
}
# ifdef ASSERT
2010-06-04 11:18:04 -07:00
SubstitutionChecker check_substitute ;
if ( block - > state ( ) ) block - > state ( ) - > values_do ( & check_substitute ) ;
block - > block_values_do ( & check_substitute ) ;
if ( block - > end ( ) & & block - > end ( ) - > state ( ) ) block - > end ( ) - > state ( ) - > values_do ( & check_substitute ) ;
2007-12-01 00:00:00 +00:00
# endif
}