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