1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "slicer/tryblocks_encoder.h" 18 #include "slicer/chronometer.h" 19 #include "slicer/common.h" 20 21 #include <assert.h> 22 23 namespace lir { 24 Visit(TryBlockEnd * try_end)25bool TryBlocksEncoder::Visit(TryBlockEnd* try_end) { 26 const dex::u4 begin_offset = try_end->try_begin->offset; 27 const dex::u4 end_offset = try_end->offset; 28 SLICER_CHECK(end_offset > begin_offset); 29 SLICER_CHECK(end_offset - begin_offset < (1 << 16)); 30 31 // generate the "try_item" 32 dex::TryBlock try_block = {}; 33 try_block.start_addr = begin_offset; 34 try_block.insn_count = end_offset - begin_offset; 35 try_block.handler_off = handlers_.size(); 36 tries_.Push(try_block); 37 38 // generate the "encoded_catch_handler" 39 dex::s4 catch_count = try_end->handlers.size(); 40 handlers_.PushSLeb128(try_end->catch_all ? -catch_count : catch_count); 41 for (int catch_index = 0; catch_index < catch_count; ++catch_index) { 42 const CatchHandler& handler = try_end->handlers[catch_index]; 43 // type_idx 44 handlers_.PushULeb128(handler.ir_type->orig_index); 45 // address 46 SLICER_CHECK(handler.label->offset != kInvalidOffset); 47 handlers_.PushULeb128(handler.label->offset); 48 } 49 if (try_end->catch_all != nullptr) { 50 // address 51 SLICER_CHECK(try_end->catch_all->offset != kInvalidOffset); 52 handlers_.PushULeb128(try_end->catch_all->offset); 53 } 54 55 return true; 56 } 57 Encode(ir::Code * ir_code,std::shared_ptr<ir::DexFile> dex_ir)58void TryBlocksEncoder::Encode(ir::Code* ir_code, std::shared_ptr<ir::DexFile> dex_ir) { 59 SLICER_CHECK(handlers_.empty()); 60 SLICER_CHECK(tries_.empty()); 61 62 // first, count the number of try blocks 63 int tries_count = 0; 64 for (auto instr : instructions_) { 65 if (instr->IsA<TryBlockEnd>()) { 66 ++tries_count; 67 } 68 } 69 SLICER_CHECK(tries_count < (1 << 16)); 70 71 // no try blocks? 72 if (tries_count == 0) { 73 ir_code->try_blocks = {}; 74 ir_code->catch_handlers = {}; 75 return; 76 } 77 78 // "encoded_catch_handler_list.size" 79 handlers_.PushULeb128(tries_count); 80 81 // generate the try blocks & encoded catch handlers 82 // 83 // NOTE: try_item[tries_count] : 84 // "Elements of the array must be non-overlapping in range and 85 // in order from low to high address. This element is only present 86 // if tries_size is non-zero" 87 // 88 // NOTE: we're not de-duplicating catch_handlers 89 // (generate one catch_handler for each try block) 90 // 91 for (auto instr : instructions_) { 92 instr->Accept(this); 93 } 94 SLICER_CHECK(!tries_.empty()); 95 SLICER_CHECK(!handlers_.empty()); 96 tries_.Seal(1); 97 handlers_.Seal(1); 98 99 // update ir::Code 100 auto tries_ptr = tries_.ptr<const dex::TryBlock>(0); 101 ir_code->try_blocks = slicer::ArrayView<const dex::TryBlock>(tries_ptr, tries_count); 102 ir_code->catch_handlers = slicer::MemView(handlers_.data(), handlers_.size()); 103 104 // attach the generated try/catch blocks to the dex IR 105 dex_ir->AttachBuffer(std::move(tries_)); 106 dex_ir->AttachBuffer(std::move(handlers_)); 107 } 108 109 } // namespace lir 110