static size_t lha_lh_new_read(void *data, uint8_t *buf) { LHANewDecoder *decoder = data; size_t result; int code; // Start of new block? while (decoder->block_remaining == 0) { if (!start_new_block(decoder)) { return 0; } } --decoder->block_remaining; // Read next command from input stream. result = 0; code = read_code(decoder); if (code < 0) { return 0; } // The code may be either a literal byte value or a copy command. if (code < 256) { output_byte(decoder, buf, &result, (uint8_t) code); } else { copy_from_history(decoder, buf, &result, code - 256 + COPY_THRESHOLD); } return result; }
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()); }