1 /*
2  * Copyright (C) 2015 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 "dex_instruction-inl.h"
18 #include "dex_instruction_iterator.h"
19 #include "gtest/gtest.h"
20 
21 namespace art {
22 
TEST(StaticGetters,PropertiesOfNopTest)23 TEST(StaticGetters, PropertiesOfNopTest) {
24   Instruction::Code nop = Instruction::NOP;
25   EXPECT_STREQ("nop", Instruction::Name(nop));
26   EXPECT_EQ(Instruction::k10x, Instruction::FormatOf(nop));
27   EXPECT_EQ(Instruction::kIndexNone, Instruction::IndexTypeOf(nop));
28   EXPECT_EQ(Instruction::kContinue, Instruction::FlagsOf(nop));
29   EXPECT_EQ(Instruction::kVerifyNothing, Instruction::VerifyFlagsOf(nop));
30 }
31 
Build45cc(uint8_t num_args,uint16_t method_idx,uint16_t proto_idx,uint16_t arg_regs,uint16_t * out)32 static void Build45cc(uint8_t num_args, uint16_t method_idx, uint16_t proto_idx,
33                       uint16_t arg_regs, uint16_t* out) {
34   // A = num argument registers
35   // B = method_idx
36   // C - G = argument registers
37   // H = proto_idx
38   //
39   // op = 0xFA
40   //
41   // format:
42   // AG op BBBB FEDC HHHH
43   out[0] = 0;
44   out[0] |= (num_args << 12);
45   out[0] |= 0x00FA;
46 
47   out[1] = method_idx;
48   out[2] = arg_regs;
49   out[3] = proto_idx;
50 }
51 
Build4rcc(uint16_t num_args,uint16_t method_idx,uint16_t proto_idx,uint16_t arg_regs_start,uint16_t * out)52 static void Build4rcc(uint16_t num_args, uint16_t method_idx, uint16_t proto_idx,
53                       uint16_t arg_regs_start, uint16_t* out) {
54   // A = num argument registers
55   // B = method_idx
56   // C = first argument register
57   // H = proto_idx
58   //
59   // op = 0xFB
60   //
61   // format:
62   // AA op BBBB CCCC HHHH
63   out[0] = 0;
64   out[0] |= (num_args << 8);
65   out[0] |= 0x00FB;
66 
67   out[1] = method_idx;
68   out[2] = arg_regs_start;
69   out[3] = proto_idx;
70 }
71 
TEST(Instruction,PropertiesOf45cc)72 TEST(Instruction, PropertiesOf45cc) {
73   uint16_t instruction[4];
74   Build45cc(/* num_args= */ 4u,
75             /* method_idx= */ 16u,
76             /* proto_idx= */ 32u,
77             /* arg_regs= */ 0xcafe,
78             instruction);
79 
80   DexInstructionIterator ins(instruction, /*dex_pc=*/ 0u);
81   ASSERT_EQ(4u, ins->SizeInCodeUnits());
82 
83   ASSERT_TRUE(ins->HasVRegA());
84   ASSERT_EQ(4, ins->VRegA());
85   ASSERT_EQ(4u, ins->VRegA_45cc());
86   ASSERT_EQ(4u, ins->VRegA_45cc(instruction[0]));
87 
88   ASSERT_TRUE(ins->HasVRegB());
89   ASSERT_EQ(16, ins->VRegB());
90   ASSERT_EQ(16u, ins->VRegB_45cc());
91 
92   ASSERT_TRUE(ins->HasVRegC());
93   ASSERT_EQ(0xe, ins->VRegC());
94   ASSERT_EQ(0xe, ins->VRegC_45cc());
95 
96   ASSERT_TRUE(ins->HasVRegH());
97   ASSERT_EQ(32, ins->VRegH());
98   ASSERT_EQ(32, ins->VRegH_45cc());
99 
100   ASSERT_TRUE(ins->HasVarArgs());
101 
102   uint32_t arg_regs[Instruction::kMaxVarArgRegs];
103   ins->GetVarArgs(arg_regs);
104   ASSERT_EQ(0xeu, arg_regs[0]);
105   ASSERT_EQ(0xfu, arg_regs[1]);
106   ASSERT_EQ(0xau, arg_regs[2]);
107   ASSERT_EQ(0xcu, arg_regs[3]);
108 }
109 
TEST(Instruction,PropertiesOf4rcc)110 TEST(Instruction, PropertiesOf4rcc) {
111   uint16_t instruction[4];
112   Build4rcc(/* num_args= */ 4u,
113             /* method_idx= */ 16u,
114             /* proto_idx= */ 32u,
115             /* arg_regs_start= */ 0xcafe,
116             instruction);
117 
118   DexInstructionIterator ins(instruction, /*dex_pc=*/ 0u);
119   ASSERT_EQ(4u, ins->SizeInCodeUnits());
120 
121   ASSERT_TRUE(ins->HasVRegA());
122   ASSERT_EQ(4, ins->VRegA());
123   ASSERT_EQ(4u, ins->VRegA_4rcc());
124   ASSERT_EQ(4u, ins->VRegA_4rcc(instruction[0]));
125 
126   ASSERT_TRUE(ins->HasVRegB());
127   ASSERT_EQ(16, ins->VRegB());
128   ASSERT_EQ(16u, ins->VRegB_4rcc());
129 
130   ASSERT_TRUE(ins->HasVRegC());
131   ASSERT_EQ(0xcafe, ins->VRegC());
132   ASSERT_EQ(0xcafe, ins->VRegC_4rcc());
133 
134   ASSERT_TRUE(ins->HasVRegH());
135   ASSERT_EQ(32, ins->VRegH());
136   ASSERT_EQ(32, ins->VRegH_4rcc());
137 
138   ASSERT_FALSE(ins->HasVarArgs());
139 }
140 
Build35c(uint16_t * out,Instruction::Code code,uint16_t method_idx,const std::vector<uint16_t> & args)141 static void Build35c(uint16_t* out,
142                      Instruction::Code code,
143                      uint16_t method_idx,
144                      const std::vector<uint16_t>& args) {
145   out[0] = 0;
146   out[0] |= (args.size() << 12);
147   out[0] |= static_cast<uint16_t>(code);
148   out[1] = method_idx;
149   size_t i = 0;
150   out[2] = 0;
151   for (; i < 4 && i < args.size(); ++i) {
152     out[2] |= args[i] << (i * 4);
153   }
154   if (args.size() == 5) {
155     out[0] |= args[4] << 8;
156   }
157 }
158 
DumpInst35c(Instruction::Code code,uint16_t method_idx,const std::vector<uint16_t> & args)159 static std::string DumpInst35c(Instruction::Code code,
160                                uint16_t method_idx,
161                                const std::vector<uint16_t>& args) {
162   uint16_t inst[6] = {};
163   Build35c(inst, code, method_idx, args);
164   return Instruction::At(inst)->DumpString(nullptr);
165 }
166 
TEST(Instruction,DumpString)167 TEST(Instruction, DumpString) {
168   EXPECT_EQ(DumpInst35c(Instruction::FILLED_NEW_ARRAY, 1234, {3, 2}),
169             "filled-new-array {v3, v2}, type@1234");
170   EXPECT_EQ(DumpInst35c(Instruction::INVOKE_VIRTUAL, 1234, {3, 2, 1, 5, 6}),
171             "invoke-virtual {v3, v2, v1, v5, v6}, thing@1234");
172   EXPECT_EQ(DumpInst35c(Instruction::INVOKE_VIRTUAL_QUICK, 1234, {3, 2, 1, 5}),
173             "invoke-virtual-quick {v3, v2, v1, v5}, thing@1234");
174   EXPECT_EQ(DumpInst35c(Instruction::INVOKE_CUSTOM, 1234, {3, 2, 1}),
175             "invoke-custom {v3, v2, v1}, thing@1234");
176 }
177 
178 }  // namespace art
179