Home | History | Annotate | Download | only in slicer
      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 
     25 bool 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 
     58 void 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