CFGBlock* add_block(int ip, bool loop=false) { CFGBlock* blk = find_block(ip); if(blk) return blk; blk = new CFGBlock(ip, loop); // Inherit the current exception handler blk->set_exception_handler(current_->exception_handler()); set_block(ip, blk); return blk; }
void build() { find_backward_gotos(); // Construct the root block specially. if(blocks_[0]) { root_ = blocks_[0]; } else { root_ = new CFGBlock(0); blocks_[0] = root_; } current_ = root_; VMMethod::Iterator iter(stream_, stream_size_); for(;;) { if(CFGBlock* next_block = find_block(iter.position())) { if(next_block->loop_p()) { // The handler wasn't setup originally, so we have to set it now. next_block->set_exception_handler(current_->exception_handler()); close_current(iter, next_block); } else { current_ = next_block; } } switch(iter.op()) { case InstructionSequence::insn_goto: case InstructionSequence::insn_goto_if_true: case InstructionSequence::insn_goto_if_false: if(iter.operand1() > iter.position()) { current_->add_child(add_block(iter.operand1())); start_new_block(iter); } else { #ifndef NDEBUG CFGBlock* loop_header = find_block(iter.operand1()); assert(loop_header); assert(loop_header->exception_handler() == current_->exception_handler()); #endif } break; case InstructionSequence::insn_setup_unwind: { assert(iter.operand1() > iter.position()); CFGBlock* handler = add_block(iter.operand1()); handler->set_exception_type(iter.operand2()); current_->add_child(handler); CFGBlock* body = start_new_block(iter); assert(body); // make sure it's not at the end. body->set_exception_handler(handler); break; } case InstructionSequence::insn_pop_unwind: { assert(current_->exception_handler()); CFGBlock* cont = start_new_block(iter); CFGBlock* current_handler = cont->exception_handler(); assert(current_handler); // Effectively pop the current handler by setting the // blocks handler (and thus all blocks after it) to the current // handlers handler. cont->set_exception_handler(current_handler->exception_handler()); break; } case InstructionSequence::insn_ensure_return: case InstructionSequence::insn_raise_exc: case InstructionSequence::insn_raise_return: case InstructionSequence::insn_raise_break: case InstructionSequence::insn_reraise: case InstructionSequence::insn_ret: start_new_block(iter); break; } if(!iter.advance()) break; } current_->set_end_ip(iter.position()); }