blob: 6047e8c74e38c2989b00f64b07db23688a02a26f [file] [log] [blame]
Eric Holkdbc36e22018-09-20 12:03:10 -07001/*
2 * Copyright (C) 2018 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_builder.h"
18
19#include "dex/descriptors_names.h"
Eric Holkdbc36e22018-09-20 12:03:10 -070020
21#include <fstream>
22#include <memory>
23
24namespace startop {
25namespace dex {
26
27using std::shared_ptr;
28using std::string;
29
Eric Holkdbc36e22018-09-20 12:03:10 -070030using ::dex::kAccPublic;
Eric Holkfaefd4f2018-10-11 16:25:57 -070031using Op = Instruction::Op;
Eric Holkdbc36e22018-09-20 12:03:10 -070032
Eric Holkd1b43832019-01-29 08:32:42 -080033using Opcode = ::art::Instruction::Code;
34
Eric Holkdbc36e22018-09-20 12:03:10 -070035const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
36const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
37
38namespace {
39// From https://source.android.com/devices/tech/dalvik/dex-format#dex-file-magic
40constexpr uint8_t kDexFileMagic[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00};
41
42// Strings lengths can be 32 bits long, but encoded as LEB128 this can take up to five bytes.
43constexpr size_t kMaxEncodedStringLength{5};
44
Eric Holkd1b43832019-01-29 08:32:42 -080045// Converts invoke-* to invoke-*/range
46constexpr Opcode InvokeToInvokeRange(Opcode opcode) {
47 switch (opcode) {
48 case ::art::Instruction::INVOKE_VIRTUAL:
49 return ::art::Instruction::INVOKE_VIRTUAL_RANGE;
50 case ::art::Instruction::INVOKE_DIRECT:
51 return ::art::Instruction::INVOKE_DIRECT_RANGE;
52 case ::art::Instruction::INVOKE_STATIC:
53 return ::art::Instruction::INVOKE_STATIC_RANGE;
54 case ::art::Instruction::INVOKE_INTERFACE:
55 return ::art::Instruction::INVOKE_INTERFACE_RANGE;
56 default:
57 LOG(FATAL) << opcode << " is not a recognized invoke opcode.";
58 UNREACHABLE();
59 }
60}
61
Eric Holkdbc36e22018-09-20 12:03:10 -070062} // namespace
63
Eric Holkfaefd4f2018-10-11 16:25:57 -070064std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
65 switch (opcode) {
66 case Instruction::Op::kReturn:
67 out << "kReturn";
68 return out;
Eric Holk3cc4afc2018-11-08 14:16:20 -080069 case Instruction::Op::kReturnObject:
70 out << "kReturnObject";
71 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -070072 case Instruction::Op::kMove:
73 out << "kMove";
74 return out;
Eric Holkd1b43832019-01-29 08:32:42 -080075 case Instruction::Op::kMoveObject:
76 out << "kMoveObject";
77 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -070078 case Instruction::Op::kInvokeVirtual:
79 out << "kInvokeVirtual";
80 return out;
Eric Holkb3927582018-11-08 16:40:16 -080081 case Instruction::Op::kInvokeDirect:
82 out << "kInvokeDirect";
83 return out;
Eric Holkc69449d2018-12-13 11:35:58 -080084 case Instruction::Op::kInvokeStatic:
85 out << "kInvokeStatic";
86 return out;
87 case Instruction::Op::kInvokeInterface:
88 out << "kInvokeInterface";
89 return out;
Eric Holkd62c5aa2018-11-01 15:50:24 -070090 case Instruction::Op::kBindLabel:
91 out << "kBindLabel";
92 return out;
93 case Instruction::Op::kBranchEqz:
94 out << "kBranchEqz";
95 return out;
Eric Holkc69449d2018-12-13 11:35:58 -080096 case Instruction::Op::kBranchNEqz:
97 out << "kBranchNEqz";
98 return out;
Eric Holkb3927582018-11-08 16:40:16 -080099 case Instruction::Op::kNew:
100 out << "kNew";
101 return out;
Eric Holk44d8cdf2018-12-17 13:35:34 -0800102 case Instruction::Op::kCheckCast:
103 out << "kCheckCast";
104 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700105 }
106}
107
Eric Holkc69449d2018-12-13 11:35:58 -0800108std::ostream& operator<<(std::ostream& out, const Value& value) {
109 if (value.is_register()) {
110 out << "Register(" << value.value() << ")";
111 } else if (value.is_parameter()) {
112 out << "Parameter(" << value.value() << ")";
113 } else if (value.is_immediate()) {
114 out << "Immediate(" << value.value() << ")";
115 } else if (value.is_string()) {
116 out << "String(" << value.value() << ")";
117 } else if (value.is_label()) {
118 out << "Label(" << value.value() << ")";
119 } else if (value.is_type()) {
120 out << "Type(" << value.value() << ")";
121 } else {
122 out << "UnknownValue";
123 }
124 return out;
125}
126
Eric Holkdbc36e22018-09-20 12:03:10 -0700127void* TrackingAllocator::Allocate(size_t size) {
128 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
129 void* raw_buffer = buffer.get();
130 allocations_[raw_buffer] = std::move(buffer);
131 return raw_buffer;
132}
133
134void TrackingAllocator::Free(void* ptr) { allocations_.erase(allocations_.find(ptr)); }
135
136// Write out a DEX file that is basically:
137//
138// package dextest;
139// public class DexTest {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700140// public static int foo(String s) { return s.length(); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700141// }
142void WriteTestDexFile(const string& filename) {
143 DexBuilder dex_file;
144
145 ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
146 cbuilder.set_source_file("dextest.java");
147
Eric Holkfaefd4f2018-10-11 16:25:57 -0700148 TypeDescriptor string_type = TypeDescriptor::FromClassname("java.lang.String");
Eric Holkdbc36e22018-09-20 12:03:10 -0700149
Eric Holkfaefd4f2018-10-11 16:25:57 -0700150 MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})};
151
152 Value result = method.MakeRegister();
153
154 MethodDeclData string_length =
155 dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()});
156
157 method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
158 method.BuildReturn(result);
Eric Holkdbc36e22018-09-20 12:03:10 -0700159
160 method.Encode();
161
162 slicer::MemView image{dex_file.CreateImage()};
163
164 std::ofstream out_file(filename);
165 out_file.write(image.ptr<const char>(), image.size());
166}
167
Eric Holkfaefd4f2018-10-11 16:25:57 -0700168TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) {
169 return TypeDescriptor{art::DotToDescriptor(name.c_str())};
170}
171
Eric Holkdbc36e22018-09-20 12:03:10 -0700172DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
173 dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
174}
175
176slicer::MemView DexBuilder::CreateImage() {
177 ::dex::Writer writer(dex_file_);
178 size_t image_size{0};
179 ::dex::u1* image = writer.CreateImage(&allocator_, &image_size);
180 return slicer::MemView{image, image_size};
181}
182
183ir::String* DexBuilder::GetOrAddString(const std::string& string) {
184 ir::String*& entry = strings_[string];
185
186 if (entry == nullptr) {
187 // Need to encode the length and then write out the bytes, including 1 byte for null terminator
188 auto buffer = std::make_unique<uint8_t[]>(string.size() + kMaxEncodedStringLength + 1);
189 uint8_t* string_data_start = ::dex::WriteULeb128(buffer.get(), string.size());
190
191 size_t header_length =
192 reinterpret_cast<uintptr_t>(string_data_start) - reinterpret_cast<uintptr_t>(buffer.get());
193
194 auto end = std::copy(string.begin(), string.end(), string_data_start);
195 *end = '\0';
196
197 entry = Alloc<ir::String>();
198 // +1 for null terminator
199 entry->data = slicer::MemView{buffer.get(), header_length + string.size() + 1};
Eric Holk3cc4afc2018-11-08 14:16:20 -0800200 ::dex::u4 const new_index = dex_file_->strings_indexes.AllocateIndex();
201 dex_file_->strings_map[new_index] = entry;
202 entry->orig_index = new_index;
Eric Holkdbc36e22018-09-20 12:03:10 -0700203 string_data_.push_back(std::move(buffer));
204 }
205 return entry;
206}
207
208ClassBuilder DexBuilder::MakeClass(const std::string& name) {
209 auto* class_def = Alloc<ir::Class>();
210 ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str()));
211 type_def->class_def = class_def;
212
213 class_def->type = type_def;
214 class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
215 class_def->access_flags = kAccPublic;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700216 return ClassBuilder{this, name, class_def};
Eric Holkdbc36e22018-09-20 12:03:10 -0700217}
218
Eric Holkdbc36e22018-09-20 12:03:10 -0700219ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
220 if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
221 return types_by_descriptor_[descriptor];
222 }
223
224 ir::Type* type = Alloc<ir::Type>();
225 type->descriptor = GetOrAddString(descriptor);
226 types_by_descriptor_[descriptor] = type;
Eric Holkb3927582018-11-08 16:40:16 -0800227 type->orig_index = dex_file_->types_indexes.AllocateIndex();
228 dex_file_->types_map[type->orig_index] = type;
Eric Holkdbc36e22018-09-20 12:03:10 -0700229 return type;
230}
231
232ir::Proto* Prototype::Encode(DexBuilder* dex) const {
233 auto* proto = dex->Alloc<ir::Proto>();
234 proto->shorty = dex->GetOrAddString(Shorty());
235 proto->return_type = dex->GetOrAddType(return_type_.descriptor());
236 if (param_types_.size() > 0) {
237 proto->param_types = dex->Alloc<ir::TypeList>();
238 for (const auto& param_type : param_types_) {
239 proto->param_types->types.push_back(dex->GetOrAddType(param_type.descriptor()));
240 }
241 } else {
242 proto->param_types = nullptr;
243 }
244 return proto;
245}
246
247std::string Prototype::Shorty() const {
248 std::string shorty;
249 shorty.append(return_type_.short_descriptor());
250 for (const auto& type_descriptor : param_types_) {
251 shorty.append(type_descriptor.short_descriptor());
252 }
253 return shorty;
254}
255
Eric Holkd1b43832019-01-29 08:32:42 -0800256const TypeDescriptor& Prototype::ArgType(size_t index) const {
257 CHECK_LT(index, param_types_.size());
258 return param_types_[index];
259}
260
Eric Holkfaefd4f2018-10-11 16:25:57 -0700261ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def)
262 : parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {}
Eric Holkdbc36e22018-09-20 12:03:10 -0700263
264MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700265 ir::MethodDecl* decl = parent_->GetOrDeclareMethod(type_descriptor_, name, prototype).decl;
Eric Holkdbc36e22018-09-20 12:03:10 -0700266
267 return MethodBuilder{parent_, class_, decl};
268}
269
270void ClassBuilder::set_source_file(const string& source) {
271 class_->source_file = parent_->GetOrAddString(source);
272}
273
274MethodBuilder::MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl)
275 : dex_{dex}, class_{class_def}, decl_{decl} {}
276
277ir::EncodedMethod* MethodBuilder::Encode() {
278 auto* method = dex_->Alloc<ir::EncodedMethod>();
279 method->decl = decl_;
280
281 // TODO: make access flags configurable
282 method->access_flags = kAccPublic | ::dex::kAccStatic;
283
284 auto* code = dex_->Alloc<ir::Code>();
Eric Holkd1b43832019-01-29 08:32:42 -0800285 CHECK(decl_->prototype != nullptr);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700286 size_t const num_args =
287 decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
Eric Holkd1b43832019-01-29 08:32:42 -0800288 code->registers = num_registers_ + num_args + kMaxScratchRegisters;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700289 code->ins_count = num_args;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700290 EncodeInstructions();
Eric Holkdbc36e22018-09-20 12:03:10 -0700291 code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
Eric Holkb3927582018-11-08 16:40:16 -0800292 size_t const return_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1;
293 code->outs_count = std::max(return_count, max_args_);
Eric Holkdbc36e22018-09-20 12:03:10 -0700294 method->code = code;
295
296 class_->direct_methods.push_back(method);
297
298 return method;
299}
300
Eric Holkfaefd4f2018-10-11 16:25:57 -0700301Value MethodBuilder::MakeRegister() { return Value::Local(num_registers_++); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700302
Eric Holkd62c5aa2018-11-01 15:50:24 -0700303Value MethodBuilder::MakeLabel() {
304 labels_.push_back({});
305 return Value::Label(labels_.size() - 1);
306}
307
Eric Holkfaefd4f2018-10-11 16:25:57 -0700308void MethodBuilder::AddInstruction(Instruction instruction) {
309 instructions_.push_back(instruction);
310}
Eric Holkdbc36e22018-09-20 12:03:10 -0700311
Eric Holkfaefd4f2018-10-11 16:25:57 -0700312void MethodBuilder::BuildReturn() { AddInstruction(Instruction::OpNoArgs(Op::kReturn)); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700313
Eric Holk3cc4afc2018-11-08 14:16:20 -0800314void MethodBuilder::BuildReturn(Value src, bool is_object) {
315 AddInstruction(Instruction::OpWithArgs(
316 is_object ? Op::kReturnObject : Op::kReturn, /*destination=*/{}, src));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700317}
318
319void MethodBuilder::BuildConst4(Value target, int value) {
Eric Holkd1b43832019-01-29 08:32:42 -0800320 CHECK_LT(value, 16);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700321 AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value)));
322}
323
Eric Holk3cc4afc2018-11-08 14:16:20 -0800324void MethodBuilder::BuildConstString(Value target, const std::string& value) {
325 const ir::String* const dex_string = dex_->GetOrAddString(value);
326 AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::String(dex_string->orig_index)));
327}
328
Eric Holkfaefd4f2018-10-11 16:25:57 -0700329void MethodBuilder::EncodeInstructions() {
330 buffer_.clear();
331 for (const auto& instruction : instructions_) {
332 EncodeInstruction(instruction);
333 }
334}
335
336void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
337 switch (instruction.opcode()) {
338 case Instruction::Op::kReturn:
Eric Holk3cc4afc2018-11-08 14:16:20 -0800339 return EncodeReturn(instruction, ::art::Instruction::RETURN);
340 case Instruction::Op::kReturnObject:
341 return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700342 case Instruction::Op::kMove:
Eric Holkd1b43832019-01-29 08:32:42 -0800343 case Instruction::Op::kMoveObject:
Eric Holkfaefd4f2018-10-11 16:25:57 -0700344 return EncodeMove(instruction);
345 case Instruction::Op::kInvokeVirtual:
Eric Holkb3927582018-11-08 16:40:16 -0800346 return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
347 case Instruction::Op::kInvokeDirect:
348 return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT);
Eric Holkc69449d2018-12-13 11:35:58 -0800349 case Instruction::Op::kInvokeStatic:
350 return EncodeInvoke(instruction, art::Instruction::INVOKE_STATIC);
351 case Instruction::Op::kInvokeInterface:
352 return EncodeInvoke(instruction, art::Instruction::INVOKE_INTERFACE);
Eric Holkd62c5aa2018-11-01 15:50:24 -0700353 case Instruction::Op::kBindLabel:
354 return BindLabel(instruction.args()[0]);
355 case Instruction::Op::kBranchEqz:
356 return EncodeBranch(art::Instruction::IF_EQZ, instruction);
Eric Holkc69449d2018-12-13 11:35:58 -0800357 case Instruction::Op::kBranchNEqz:
358 return EncodeBranch(art::Instruction::IF_NEZ, instruction);
Eric Holkb3927582018-11-08 16:40:16 -0800359 case Instruction::Op::kNew:
360 return EncodeNew(instruction);
Eric Holk44d8cdf2018-12-17 13:35:34 -0800361 case Instruction::Op::kCheckCast:
362 return EncodeCast(instruction);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700363 }
364}
365
Eric Holk3cc4afc2018-11-08 14:16:20 -0800366void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) {
Eric Holkd1b43832019-01-29 08:32:42 -0800367 CHECK(!instruction.dest().has_value());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700368 if (instruction.args().size() == 0) {
Eric Holk1c0f3f02018-11-09 13:48:59 -0800369 Encode10x(art::Instruction::RETURN_VOID);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700370 } else {
Eric Holkd1b43832019-01-29 08:32:42 -0800371 CHECK_EQ(1, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700372 size_t source = RegisterValue(instruction.args()[0]);
Eric Holk1c0f3f02018-11-09 13:48:59 -0800373 Encode11x(opcode, source);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700374 }
375}
376
377void MethodBuilder::EncodeMove(const Instruction& instruction) {
Eric Holkd1b43832019-01-29 08:32:42 -0800378 CHECK(Instruction::Op::kMove == instruction.opcode() ||
379 Instruction::Op::kMoveObject == instruction.opcode());
380 CHECK(instruction.dest().has_value());
381 CHECK(instruction.dest()->is_variable());
382 CHECK_EQ(1, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700383
384 const Value& source = instruction.args()[0];
385
386 if (source.is_immediate()) {
387 // TODO: support more registers
Eric Holkd1b43832019-01-29 08:32:42 -0800388 CHECK_LT(RegisterValue(*instruction.dest()), 16);
Eric Holk1c0f3f02018-11-09 13:48:59 -0800389 Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value());
Eric Holk3cc4afc2018-11-08 14:16:20 -0800390 } else if (source.is_string()) {
391 constexpr size_t kMaxRegisters = 256;
Eric Holkd1b43832019-01-29 08:32:42 -0800392 CHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
393 CHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
Eric Holk1c0f3f02018-11-09 13:48:59 -0800394 Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value());
Eric Holkd1b43832019-01-29 08:32:42 -0800395 } else if (source.is_variable()) {
396 // For the moment, we only use this when we need to reshuffle registers for
397 // an invoke instruction, meaning we are too big for the 4-bit version.
398 // We'll err on the side of caution and always generate the 16-bit form of
399 // the instruction.
400 Opcode opcode = instruction.opcode() == Instruction::Op::kMove
401 ? ::art::Instruction::MOVE_16
402 : ::art::Instruction::MOVE_OBJECT_16;
403 Encode32x(opcode, RegisterValue(*instruction.dest()), RegisterValue(source));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700404 } else {
405 UNIMPLEMENTED(FATAL);
406 }
407}
408
Eric Holkb3927582018-11-08 16:40:16 -0800409void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) {
Eric Holk1c0f3f02018-11-09 13:48:59 -0800410 constexpr size_t kMaxArgs = 5;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700411
Eric Holkd1b43832019-01-29 08:32:42 -0800412 // Currently, we only support up to 5 arguments.
Eric Holk1c0f3f02018-11-09 13:48:59 -0800413 CHECK_LE(instruction.args().size(), kMaxArgs);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700414
Eric Holk1c0f3f02018-11-09 13:48:59 -0800415 uint8_t arguments[kMaxArgs]{};
Eric Holkd1b43832019-01-29 08:32:42 -0800416 bool has_long_args = false;
Eric Holk1c0f3f02018-11-09 13:48:59 -0800417 for (size_t i = 0; i < instruction.args().size(); ++i) {
418 CHECK(instruction.args()[i].is_variable());
419 arguments[i] = RegisterValue(instruction.args()[i]);
Eric Holkd1b43832019-01-29 08:32:42 -0800420 if (!IsShortRegister(arguments[i])) {
421 has_long_args = true;
422 }
Eric Holkb3927582018-11-08 16:40:16 -0800423 }
Eric Holk1c0f3f02018-11-09 13:48:59 -0800424
Eric Holkd1b43832019-01-29 08:32:42 -0800425 if (has_long_args) {
426 // Some of the registers don't fit in the four bit short form of the invoke
427 // instruction, so we need to do an invoke/range. To do this, we need to
428 // first move all the arguments into contiguous temporary registers.
Chih-Hung Hsieh2b61bdd2019-02-05 17:08:30 -0800429 std::array<Value, kMaxArgs> scratch = GetScratchRegisters<kMaxArgs>();
Eric Holkd1b43832019-01-29 08:32:42 -0800430
431 const auto& prototype = dex_->GetPrototypeByMethodId(instruction.method_id());
432 CHECK(prototype.has_value());
433
434 for (size_t i = 0; i < instruction.args().size(); ++i) {
435 Instruction::Op move_op;
436 if (opcode == ::art::Instruction::INVOKE_VIRTUAL ||
437 opcode == ::art::Instruction::INVOKE_DIRECT) {
438 // In this case, there is an implicit `this` argument, which is always an object.
439 if (i == 0) {
440 move_op = Instruction::Op::kMoveObject;
441 } else {
442 move_op = prototype->ArgType(i - 1).is_object() ? Instruction::Op::kMoveObject
443 : Instruction::Op::kMove;
444 }
445 } else {
446 move_op = prototype->ArgType(i).is_object() ? Instruction::Op::kMoveObject
447 : Instruction::Op::kMove;
448 }
449
450 EncodeMove(Instruction::OpWithArgs(move_op, scratch[i], instruction.args()[i]));
451 }
452
453 Encode3rc(InvokeToInvokeRange(opcode),
454 instruction.args().size(),
455 instruction.method_id(),
456 RegisterValue(scratch[0]));
457 } else {
458 Encode35c(opcode,
459 instruction.args().size(),
460 instruction.method_id(),
461 arguments[0],
462 arguments[1],
463 arguments[2],
464 arguments[3],
465 arguments[4]);
466 }
Eric Holkb3927582018-11-08 16:40:16 -0800467
468 // If there is a return value, add a move-result instruction
Eric Holkfaefd4f2018-10-11 16:25:57 -0700469 if (instruction.dest().has_value()) {
Eric Holkc69449d2018-12-13 11:35:58 -0800470 Encode11x(instruction.result_is_object() ? art::Instruction::MOVE_RESULT_OBJECT
471 : art::Instruction::MOVE_RESULT,
472 RegisterValue(*instruction.dest()));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700473 }
Eric Holkb3927582018-11-08 16:40:16 -0800474
475 max_args_ = std::max(max_args_, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700476}
477
Eric Holkd62c5aa2018-11-01 15:50:24 -0700478// Encodes a conditional branch that tests a single argument.
479void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& instruction) {
480 const auto& args = instruction.args();
481 const auto& test_value = args[0];
482 const auto& branch_target = args[1];
483 CHECK_EQ(2, args.size());
484 CHECK(test_value.is_variable());
485 CHECK(branch_target.is_label());
486
487 size_t instruction_offset = buffer_.size();
Eric Holk1c0f3f02018-11-09 13:48:59 -0800488 size_t field_offset = buffer_.size() + 1;
489 Encode21c(
490 op, RegisterValue(test_value), LabelValue(branch_target, instruction_offset, field_offset));
Eric Holkd62c5aa2018-11-01 15:50:24 -0700491}
492
Eric Holkb3927582018-11-08 16:40:16 -0800493void MethodBuilder::EncodeNew(const Instruction& instruction) {
Eric Holkd1b43832019-01-29 08:32:42 -0800494 CHECK_EQ(Instruction::Op::kNew, instruction.opcode());
495 CHECK(instruction.dest().has_value());
496 CHECK(instruction.dest()->is_variable());
497 CHECK_EQ(1, instruction.args().size());
Eric Holkb3927582018-11-08 16:40:16 -0800498
499 const Value& type = instruction.args()[0];
Eric Holkd1b43832019-01-29 08:32:42 -0800500 CHECK_LT(RegisterValue(*instruction.dest()), 256);
501 CHECK(type.is_type());
Eric Holk1c0f3f02018-11-09 13:48:59 -0800502 Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
Eric Holkb3927582018-11-08 16:40:16 -0800503}
504
Eric Holk44d8cdf2018-12-17 13:35:34 -0800505void MethodBuilder::EncodeCast(const Instruction& instruction) {
Eric Holkd1b43832019-01-29 08:32:42 -0800506 CHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
507 CHECK(instruction.dest().has_value());
508 CHECK(instruction.dest()->is_variable());
509 CHECK_EQ(1, instruction.args().size());
Eric Holk44d8cdf2018-12-17 13:35:34 -0800510
511 const Value& type = instruction.args()[0];
Eric Holkd1b43832019-01-29 08:32:42 -0800512 CHECK_LT(RegisterValue(*instruction.dest()), 256);
513 CHECK(type.is_type());
Eric Holk44d8cdf2018-12-17 13:35:34 -0800514 Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
515}
516
Eric Holkd62c5aa2018-11-01 15:50:24 -0700517size_t MethodBuilder::RegisterValue(const Value& value) const {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700518 if (value.is_register()) {
519 return value.value();
520 } else if (value.is_parameter()) {
Eric Holkd1b43832019-01-29 08:32:42 -0800521 return value.value() + num_registers_ + kMaxScratchRegisters;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700522 }
Eric Holkd1b43832019-01-29 08:32:42 -0800523 CHECK(false && "Must be either a parameter or a register");
Eric Holkfaefd4f2018-10-11 16:25:57 -0700524 return 0;
525}
526
Eric Holkd62c5aa2018-11-01 15:50:24 -0700527void MethodBuilder::BindLabel(const Value& label_id) {
528 CHECK(label_id.is_label());
529
530 LabelData& label = labels_[label_id.value()];
531 CHECK(!label.bound_address.has_value());
532
533 label.bound_address = buffer_.size();
534
535 // patch any forward references to this label.
536 for (const auto& ref : label.references) {
537 buffer_[ref.field_offset] = *label.bound_address - ref.instruction_offset;
538 }
539 // No point keeping these around anymore.
540 label.references.clear();
541}
542
543::dex::u2 MethodBuilder::LabelValue(const Value& label_id, size_t instruction_offset,
544 size_t field_offset) {
545 CHECK(label_id.is_label());
546 LabelData& label = labels_[label_id.value()];
547
548 // Short-circuit if the label is already bound.
549 if (label.bound_address.has_value()) {
550 return *label.bound_address - instruction_offset;
551 }
552
553 // Otherwise, save a reference to where we need to back-patch later.
554 label.references.push_front(LabelReference{instruction_offset, field_offset});
555 return 0;
556}
557
Eric Holkfaefd4f2018-10-11 16:25:57 -0700558const MethodDeclData& DexBuilder::GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
559 Prototype prototype) {
560 MethodDeclData& entry = method_id_map_[{type, name, prototype}];
561
562 if (entry.decl == nullptr) {
563 // This method has not already been declared, so declare it.
564 ir::MethodDecl* decl = dex_file_->Alloc<ir::MethodDecl>();
565 // The method id is the last added method.
566 size_t id = dex_file_->methods.size() - 1;
567
568 ir::String* dex_name{GetOrAddString(name)};
569 decl->name = dex_name;
570 decl->parent = GetOrAddType(type.descriptor());
571 decl->prototype = GetOrEncodeProto(prototype);
572
573 // update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc)
574 auto new_index = dex_file_->methods_indexes.AllocateIndex();
575 auto& ir_node = dex_file_->methods_map[new_index];
Eric Holkd1b43832019-01-29 08:32:42 -0800576 CHECK(ir_node == nullptr);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700577 ir_node = decl;
Eric Holkc69449d2018-12-13 11:35:58 -0800578 decl->orig_index = decl->index = new_index;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700579
580 entry = {id, decl};
581 }
582
583 return entry;
584}
585
Eric Holkd1b43832019-01-29 08:32:42 -0800586std::optional<const Prototype> DexBuilder::GetPrototypeByMethodId(size_t method_id) const {
587 for (const auto& entry : method_id_map_) {
588 if (entry.second.id == method_id) {
589 return entry.first.prototype;
590 }
591 }
592 return {};
593}
594
Eric Holkfaefd4f2018-10-11 16:25:57 -0700595ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) {
596 ir::Proto*& ir_proto = proto_map_[prototype];
597 if (ir_proto == nullptr) {
598 ir_proto = prototype.Encode(this);
599 }
600 return ir_proto;
Eric Holkdbc36e22018-09-20 12:03:10 -0700601}
602
603} // namespace dex
604} // namespace startop