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 struct TryBlockEndVisitor : public Visitor { 64 int tries_count = 0; 65 bool Visit(TryBlockEnd* try_end) override { 66 ++tries_count; 67 return true; 68 } 69 }; 70 TryBlockEndVisitor visitor; 71 for (auto instr : instructions_) { 72 instr->Accept(&visitor); 73 } 74 int tries_count = visitor.tries_count; 75 SLICER_CHECK(tries_count < (1 << 16)); 76 77 // no try blocks? 78 if (tries_count == 0) { 79 ir_code->try_blocks = {}; 80 ir_code->catch_handlers = {}; 81 return; 82 } 83 84 // "encoded_catch_handler_list.size" 85 handlers_.PushULeb128(tries_count); 86 87 // generate the try blocks & encoded catch handlers 88 // 89 // NOTE: try_item[tries_count] : 90 // "Elements of the array must be non-overlapping in range and 91 // in order from low to high address. This element is only present 92 // if tries_size is non-zero" 93 // 94 // NOTE: we're not de-duplicating catch_handlers 95 // (generate one catch_handler for each try block) 96 // 97 for (auto instr : instructions_) { 98 instr->Accept(this); 99 } 100 SLICER_CHECK(!tries_.empty()); 101 SLICER_CHECK(!handlers_.empty()); 102 tries_.Seal(1); 103 handlers_.Seal(1); 104 105 // update ir::Code 106 auto tries_ptr = tries_.ptr<const dex::TryBlock>(0); 107 ir_code->try_blocks = slicer::ArrayView<const dex::TryBlock>(tries_ptr, tries_count); 108 ir_code->catch_handlers = slicer::MemView(handlers_.data(), handlers_.size()); 109 110 // attach the generated try/catch blocks to the dex IR 111 dex_ir->AttachBuffer(std::move(tries_)); 112 dex_ir->AttachBuffer(std::move(handlers_)); 113 } 114 115 } // namespace lir 116