blob: 50cf5a50d7a8bbd0ccef8c2e31c7e9064bfe29d9 [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
Eric Holkdbc36e22018-09-20 12:03:10 -070019#include <fstream>
20#include <memory>
21
22namespace startop {
23namespace dex {
24
25using std::shared_ptr;
26using std::string;
27
Eric Holkdbc36e22018-09-20 12:03:10 -070028using ::dex::kAccPublic;
Eric Holkfaefd4f2018-10-11 16:25:57 -070029using Op = Instruction::Op;
Eric Holkdbc36e22018-09-20 12:03:10 -070030
31const TypeDescriptor TypeDescriptor::Int() { return TypeDescriptor{"I"}; };
32const TypeDescriptor TypeDescriptor::Void() { return TypeDescriptor{"V"}; };
33
34namespace {
35// From https://source.android.com/devices/tech/dalvik/dex-format#dex-file-magic
36constexpr uint8_t kDexFileMagic[]{0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x38, 0x00};
37
38// Strings lengths can be 32 bits long, but encoded as LEB128 this can take up to five bytes.
39constexpr size_t kMaxEncodedStringLength{5};
40
Eric Holkd1b43832019-01-29 08:32:42 -080041// Converts invoke-* to invoke-*/range
Orion Hodson59d07202019-10-31 15:25:33 +000042constexpr ::dex::Opcode InvokeToInvokeRange(::dex::Opcode opcode) {
Eric Holkd1b43832019-01-29 08:32:42 -080043 switch (opcode) {
Orion Hodson59d07202019-10-31 15:25:33 +000044 case ::dex::Opcode::OP_INVOKE_VIRTUAL:
45 return ::dex::Opcode::OP_INVOKE_VIRTUAL_RANGE;
46 case ::dex::Opcode::OP_INVOKE_DIRECT:
47 return ::dex::Opcode::OP_INVOKE_DIRECT_RANGE;
48 case ::dex::Opcode::OP_INVOKE_STATIC:
49 return ::dex::Opcode::OP_INVOKE_STATIC_RANGE;
50 case ::dex::Opcode::OP_INVOKE_INTERFACE:
51 return ::dex::Opcode::OP_INVOKE_INTERFACE_RANGE;
Eric Holkd1b43832019-01-29 08:32:42 -080052 default:
53 LOG(FATAL) << opcode << " is not a recognized invoke opcode.";
Orion Hodson59d07202019-10-31 15:25:33 +000054 __builtin_unreachable();
Eric Holkd1b43832019-01-29 08:32:42 -080055 }
56}
57
Orion Hodson59d07202019-10-31 15:25:33 +000058std::string DotToDescriptor(const char* class_name) {
59 std::string descriptor(class_name);
60 std::replace(descriptor.begin(), descriptor.end(), '.', '/');
61 if (descriptor.length() > 0 && descriptor[0] != '[') {
62 descriptor = "L" + descriptor + ";";
63 }
64 return descriptor;
65}
66
Eric Holkdbc36e22018-09-20 12:03:10 -070067} // namespace
68
Eric Holkfaefd4f2018-10-11 16:25:57 -070069std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
70 switch (opcode) {
71 case Instruction::Op::kReturn:
72 out << "kReturn";
73 return out;
Eric Holk3cc4afc2018-11-08 14:16:20 -080074 case Instruction::Op::kReturnObject:
75 out << "kReturnObject";
76 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -070077 case Instruction::Op::kMove:
78 out << "kMove";
79 return out;
Eric Holkd1b43832019-01-29 08:32:42 -080080 case Instruction::Op::kMoveObject:
81 out << "kMoveObject";
82 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -070083 case Instruction::Op::kInvokeVirtual:
84 out << "kInvokeVirtual";
85 return out;
Eric Holkb3927582018-11-08 16:40:16 -080086 case Instruction::Op::kInvokeDirect:
87 out << "kInvokeDirect";
88 return out;
Eric Holkc69449d2018-12-13 11:35:58 -080089 case Instruction::Op::kInvokeStatic:
90 out << "kInvokeStatic";
91 return out;
92 case Instruction::Op::kInvokeInterface:
93 out << "kInvokeInterface";
94 return out;
Eric Holkd62c5aa2018-11-01 15:50:24 -070095 case Instruction::Op::kBindLabel:
96 out << "kBindLabel";
97 return out;
98 case Instruction::Op::kBranchEqz:
99 out << "kBranchEqz";
100 return out;
Eric Holkc69449d2018-12-13 11:35:58 -0800101 case Instruction::Op::kBranchNEqz:
102 out << "kBranchNEqz";
103 return out;
Eric Holkb3927582018-11-08 16:40:16 -0800104 case Instruction::Op::kNew:
105 out << "kNew";
106 return out;
Eric Holk44d8cdf2018-12-17 13:35:34 -0800107 case Instruction::Op::kCheckCast:
108 out << "kCheckCast";
109 return out;
Eric Holk3092f992019-07-25 15:14:01 -0700110 case Instruction::Op::kGetStaticField:
111 out << "kGetStaticField";
112 return out;
Eric Holk70445d02019-07-26 09:37:46 -0700113 case Instruction::Op::kSetStaticField:
114 out << "kSetStaticField";
115 return out;
Eric Holkf3b95892019-07-30 14:47:06 -0700116 case Instruction::Op::kGetInstanceField:
117 out << "kGetInstanceField";
118 return out;
119 case Instruction::Op::kSetInstanceField:
120 out << "kSetInstanceField";
121 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700122 }
123}
124
Eric Holkc69449d2018-12-13 11:35:58 -0800125std::ostream& operator<<(std::ostream& out, const Value& value) {
126 if (value.is_register()) {
127 out << "Register(" << value.value() << ")";
128 } else if (value.is_parameter()) {
129 out << "Parameter(" << value.value() << ")";
130 } else if (value.is_immediate()) {
131 out << "Immediate(" << value.value() << ")";
132 } else if (value.is_string()) {
133 out << "String(" << value.value() << ")";
134 } else if (value.is_label()) {
135 out << "Label(" << value.value() << ")";
136 } else if (value.is_type()) {
137 out << "Type(" << value.value() << ")";
138 } else {
139 out << "UnknownValue";
140 }
141 return out;
142}
143
Eric Holkdbc36e22018-09-20 12:03:10 -0700144void* TrackingAllocator::Allocate(size_t size) {
145 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
146 void* raw_buffer = buffer.get();
147 allocations_[raw_buffer] = std::move(buffer);
148 return raw_buffer;
149}
150
151void TrackingAllocator::Free(void* ptr) { allocations_.erase(allocations_.find(ptr)); }
152
153// Write out a DEX file that is basically:
154//
155// package dextest;
156// public class DexTest {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700157// public static int foo(String s) { return s.length(); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700158// }
159void WriteTestDexFile(const string& filename) {
160 DexBuilder dex_file;
161
162 ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
163 cbuilder.set_source_file("dextest.java");
164
Eric Holkfaefd4f2018-10-11 16:25:57 -0700165 TypeDescriptor string_type = TypeDescriptor::FromClassname("java.lang.String");
Eric Holkdbc36e22018-09-20 12:03:10 -0700166
Eric Holkfaefd4f2018-10-11 16:25:57 -0700167 MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})};
168
Eric Holk5c6a1a52019-09-17 13:28:34 -0700169 LiveRegister result = method.AllocRegister();
Eric Holkfaefd4f2018-10-11 16:25:57 -0700170
171 MethodDeclData string_length =
172 dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()});
173
174 method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
175 method.BuildReturn(result);
Eric Holkdbc36e22018-09-20 12:03:10 -0700176
177 method.Encode();
178
179 slicer::MemView image{dex_file.CreateImage()};
180
181 std::ofstream out_file(filename);
182 out_file.write(image.ptr<const char>(), image.size());
183}
184
Eric Holkfaefd4f2018-10-11 16:25:57 -0700185TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) {
Orion Hodson59d07202019-10-31 15:25:33 +0000186 return TypeDescriptor{DotToDescriptor(name.c_str())};
Eric Holkfaefd4f2018-10-11 16:25:57 -0700187}
188
Eric Holkdbc36e22018-09-20 12:03:10 -0700189DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
190 dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
191}
192
193slicer::MemView DexBuilder::CreateImage() {
194 ::dex::Writer writer(dex_file_);
195 size_t image_size{0};
196 ::dex::u1* image = writer.CreateImage(&allocator_, &image_size);
197 return slicer::MemView{image, image_size};
198}
199
200ir::String* DexBuilder::GetOrAddString(const std::string& string) {
201 ir::String*& entry = strings_[string];
202
203 if (entry == nullptr) {
204 // Need to encode the length and then write out the bytes, including 1 byte for null terminator
205 auto buffer = std::make_unique<uint8_t[]>(string.size() + kMaxEncodedStringLength + 1);
206 uint8_t* string_data_start = ::dex::WriteULeb128(buffer.get(), string.size());
207
208 size_t header_length =
209 reinterpret_cast<uintptr_t>(string_data_start) - reinterpret_cast<uintptr_t>(buffer.get());
210
211 auto end = std::copy(string.begin(), string.end(), string_data_start);
212 *end = '\0';
213
214 entry = Alloc<ir::String>();
215 // +1 for null terminator
216 entry->data = slicer::MemView{buffer.get(), header_length + string.size() + 1};
Eric Holk3cc4afc2018-11-08 14:16:20 -0800217 ::dex::u4 const new_index = dex_file_->strings_indexes.AllocateIndex();
218 dex_file_->strings_map[new_index] = entry;
219 entry->orig_index = new_index;
Eric Holkdbc36e22018-09-20 12:03:10 -0700220 string_data_.push_back(std::move(buffer));
221 }
222 return entry;
223}
224
225ClassBuilder DexBuilder::MakeClass(const std::string& name) {
226 auto* class_def = Alloc<ir::Class>();
Orion Hodson59d07202019-10-31 15:25:33 +0000227 ir::Type* type_def = GetOrAddType(DotToDescriptor(name.c_str()));
Eric Holkdbc36e22018-09-20 12:03:10 -0700228 type_def->class_def = class_def;
229
230 class_def->type = type_def;
Orion Hodson59d07202019-10-31 15:25:33 +0000231 class_def->super_class = GetOrAddType(DotToDescriptor("java.lang.Object"));
Eric Holkdbc36e22018-09-20 12:03:10 -0700232 class_def->access_flags = kAccPublic;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700233 return ClassBuilder{this, name, class_def};
Eric Holkdbc36e22018-09-20 12:03:10 -0700234}
235
Eric Holkdbc36e22018-09-20 12:03:10 -0700236ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
237 if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
238 return types_by_descriptor_[descriptor];
239 }
240
241 ir::Type* type = Alloc<ir::Type>();
242 type->descriptor = GetOrAddString(descriptor);
243 types_by_descriptor_[descriptor] = type;
Eric Holkb3927582018-11-08 16:40:16 -0800244 type->orig_index = dex_file_->types_indexes.AllocateIndex();
245 dex_file_->types_map[type->orig_index] = type;
Eric Holkdbc36e22018-09-20 12:03:10 -0700246 return type;
247}
248
Eric Holk3092f992019-07-25 15:14:01 -0700249ir::FieldDecl* DexBuilder::GetOrAddField(TypeDescriptor parent, const std::string& name,
250 TypeDescriptor type) {
251 const auto key = std::make_tuple(parent, name);
252 if (field_decls_by_key_.find(key) != field_decls_by_key_.end()) {
253 return field_decls_by_key_[key];
254 }
255
256 ir::FieldDecl* field = Alloc<ir::FieldDecl>();
257 field->parent = GetOrAddType(parent);
258 field->name = GetOrAddString(name);
259 field->type = GetOrAddType(type);
Eric Holkf3b95892019-07-30 14:47:06 -0700260 field->orig_index = dex_file_->fields_indexes.AllocateIndex();
Eric Holk3092f992019-07-25 15:14:01 -0700261 dex_file_->fields_map[field->orig_index] = field;
262 field_decls_by_key_[key] = field;
263 return field;
264}
265
Eric Holkdbc36e22018-09-20 12:03:10 -0700266ir::Proto* Prototype::Encode(DexBuilder* dex) const {
267 auto* proto = dex->Alloc<ir::Proto>();
268 proto->shorty = dex->GetOrAddString(Shorty());
269 proto->return_type = dex->GetOrAddType(return_type_.descriptor());
270 if (param_types_.size() > 0) {
271 proto->param_types = dex->Alloc<ir::TypeList>();
272 for (const auto& param_type : param_types_) {
273 proto->param_types->types.push_back(dex->GetOrAddType(param_type.descriptor()));
274 }
275 } else {
276 proto->param_types = nullptr;
277 }
278 return proto;
279}
280
281std::string Prototype::Shorty() const {
282 std::string shorty;
283 shorty.append(return_type_.short_descriptor());
284 for (const auto& type_descriptor : param_types_) {
285 shorty.append(type_descriptor.short_descriptor());
286 }
287 return shorty;
288}
289
Eric Holkd1b43832019-01-29 08:32:42 -0800290const TypeDescriptor& Prototype::ArgType(size_t index) const {
291 CHECK_LT(index, param_types_.size());
292 return param_types_[index];
293}
294
Eric Holkfaefd4f2018-10-11 16:25:57 -0700295ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def)
296 : parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {}
Eric Holkdbc36e22018-09-20 12:03:10 -0700297
298MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700299 ir::MethodDecl* decl = parent_->GetOrDeclareMethod(type_descriptor_, name, prototype).decl;
Eric Holkdbc36e22018-09-20 12:03:10 -0700300
301 return MethodBuilder{parent_, class_, decl};
302}
303
304void ClassBuilder::set_source_file(const string& source) {
305 class_->source_file = parent_->GetOrAddString(source);
306}
307
308MethodBuilder::MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl)
309 : dex_{dex}, class_{class_def}, decl_{decl} {}
310
311ir::EncodedMethod* MethodBuilder::Encode() {
312 auto* method = dex_->Alloc<ir::EncodedMethod>();
313 method->decl = decl_;
314
315 // TODO: make access flags configurable
316 method->access_flags = kAccPublic | ::dex::kAccStatic;
317
318 auto* code = dex_->Alloc<ir::Code>();
Eric Holkd1b43832019-01-29 08:32:42 -0800319 CHECK(decl_->prototype != nullptr);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700320 size_t const num_args =
321 decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
Eric Holk5c6a1a52019-09-17 13:28:34 -0700322 code->registers = NumRegisters() + num_args + kMaxScratchRegisters;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700323 code->ins_count = num_args;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700324 EncodeInstructions();
Eric Holkdbc36e22018-09-20 12:03:10 -0700325 code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
Eric Holkb3927582018-11-08 16:40:16 -0800326 size_t const return_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1;
327 code->outs_count = std::max(return_count, max_args_);
Eric Holkdbc36e22018-09-20 12:03:10 -0700328 method->code = code;
329
330 class_->direct_methods.push_back(method);
331
332 return method;
333}
334
Eric Holk5c6a1a52019-09-17 13:28:34 -0700335LiveRegister MethodBuilder::AllocRegister() {
336 // Find a free register
337 for (size_t i = 0; i < register_liveness_.size(); ++i) {
338 if (!register_liveness_[i]) {
339 register_liveness_[i] = true;
340 return LiveRegister{&register_liveness_, i};
341 }
342 }
343
344 // If we get here, all the registers are in use, so we have to allocate a new
345 // one.
346 register_liveness_.push_back(true);
347 return LiveRegister{&register_liveness_, register_liveness_.size() - 1};
348}
Eric Holkdbc36e22018-09-20 12:03:10 -0700349
Eric Holkd62c5aa2018-11-01 15:50:24 -0700350Value MethodBuilder::MakeLabel() {
351 labels_.push_back({});
352 return Value::Label(labels_.size() - 1);
353}
354
Eric Holkfaefd4f2018-10-11 16:25:57 -0700355void MethodBuilder::AddInstruction(Instruction instruction) {
356 instructions_.push_back(instruction);
357}
Eric Holkdbc36e22018-09-20 12:03:10 -0700358
Eric Holkfaefd4f2018-10-11 16:25:57 -0700359void MethodBuilder::BuildReturn() { AddInstruction(Instruction::OpNoArgs(Op::kReturn)); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700360
Eric Holk3cc4afc2018-11-08 14:16:20 -0800361void MethodBuilder::BuildReturn(Value src, bool is_object) {
362 AddInstruction(Instruction::OpWithArgs(
363 is_object ? Op::kReturnObject : Op::kReturn, /*destination=*/{}, src));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700364}
365
366void MethodBuilder::BuildConst4(Value target, int value) {
Eric Holkd1b43832019-01-29 08:32:42 -0800367 CHECK_LT(value, 16);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700368 AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value)));
369}
370
Eric Holk3cc4afc2018-11-08 14:16:20 -0800371void MethodBuilder::BuildConstString(Value target, const std::string& value) {
372 const ir::String* const dex_string = dex_->GetOrAddString(value);
373 AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::String(dex_string->orig_index)));
374}
375
Eric Holkfaefd4f2018-10-11 16:25:57 -0700376void MethodBuilder::EncodeInstructions() {
377 buffer_.clear();
378 for (const auto& instruction : instructions_) {
379 EncodeInstruction(instruction);
380 }
381}
382
383void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
384 switch (instruction.opcode()) {
385 case Instruction::Op::kReturn:
Orion Hodson59d07202019-10-31 15:25:33 +0000386 return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN);
Eric Holk3cc4afc2018-11-08 14:16:20 -0800387 case Instruction::Op::kReturnObject:
Orion Hodson59d07202019-10-31 15:25:33 +0000388 return EncodeReturn(instruction, ::dex::Opcode::OP_RETURN_OBJECT);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700389 case Instruction::Op::kMove:
Eric Holkd1b43832019-01-29 08:32:42 -0800390 case Instruction::Op::kMoveObject:
Eric Holkfaefd4f2018-10-11 16:25:57 -0700391 return EncodeMove(instruction);
392 case Instruction::Op::kInvokeVirtual:
Orion Hodson59d07202019-10-31 15:25:33 +0000393 return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_VIRTUAL);
Eric Holkb3927582018-11-08 16:40:16 -0800394 case Instruction::Op::kInvokeDirect:
Orion Hodson59d07202019-10-31 15:25:33 +0000395 return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_DIRECT);
Eric Holkc69449d2018-12-13 11:35:58 -0800396 case Instruction::Op::kInvokeStatic:
Orion Hodson59d07202019-10-31 15:25:33 +0000397 return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_STATIC);
Eric Holkc69449d2018-12-13 11:35:58 -0800398 case Instruction::Op::kInvokeInterface:
Orion Hodson59d07202019-10-31 15:25:33 +0000399 return EncodeInvoke(instruction, ::dex::Opcode::OP_INVOKE_INTERFACE);
Eric Holkd62c5aa2018-11-01 15:50:24 -0700400 case Instruction::Op::kBindLabel:
401 return BindLabel(instruction.args()[0]);
402 case Instruction::Op::kBranchEqz:
Orion Hodson59d07202019-10-31 15:25:33 +0000403 return EncodeBranch(::dex::Opcode::OP_IF_EQZ, instruction);
Eric Holkc69449d2018-12-13 11:35:58 -0800404 case Instruction::Op::kBranchNEqz:
Orion Hodson59d07202019-10-31 15:25:33 +0000405 return EncodeBranch(::dex::Opcode::OP_IF_NEZ, instruction);
Eric Holkb3927582018-11-08 16:40:16 -0800406 case Instruction::Op::kNew:
407 return EncodeNew(instruction);
Eric Holk44d8cdf2018-12-17 13:35:34 -0800408 case Instruction::Op::kCheckCast:
409 return EncodeCast(instruction);
Eric Holk3092f992019-07-25 15:14:01 -0700410 case Instruction::Op::kGetStaticField:
Eric Holk70445d02019-07-26 09:37:46 -0700411 case Instruction::Op::kSetStaticField:
Eric Holkf3b95892019-07-30 14:47:06 -0700412 case Instruction::Op::kGetInstanceField:
413 case Instruction::Op::kSetInstanceField:
414 return EncodeFieldOp(instruction);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700415 }
416}
417
Orion Hodson59d07202019-10-31 15:25:33 +0000418void MethodBuilder::EncodeReturn(const Instruction& instruction, ::dex::Opcode opcode) {
Eric Holkd1b43832019-01-29 08:32:42 -0800419 CHECK(!instruction.dest().has_value());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700420 if (instruction.args().size() == 0) {
Orion Hodson59d07202019-10-31 15:25:33 +0000421 Encode10x(::dex::Opcode::OP_RETURN_VOID);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700422 } else {
Eric Holkd1b43832019-01-29 08:32:42 -0800423 CHECK_EQ(1, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700424 size_t source = RegisterValue(instruction.args()[0]);
Eric Holk1c0f3f02018-11-09 13:48:59 -0800425 Encode11x(opcode, source);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700426 }
427}
428
429void MethodBuilder::EncodeMove(const Instruction& instruction) {
Eric Holkd1b43832019-01-29 08:32:42 -0800430 CHECK(Instruction::Op::kMove == instruction.opcode() ||
431 Instruction::Op::kMoveObject == instruction.opcode());
432 CHECK(instruction.dest().has_value());
433 CHECK(instruction.dest()->is_variable());
434 CHECK_EQ(1, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700435
436 const Value& source = instruction.args()[0];
437
438 if (source.is_immediate()) {
439 // TODO: support more registers
Eric Holkd1b43832019-01-29 08:32:42 -0800440 CHECK_LT(RegisterValue(*instruction.dest()), 16);
Orion Hodson59d07202019-10-31 15:25:33 +0000441 Encode11n(::dex::Opcode::OP_CONST_4, RegisterValue(*instruction.dest()), source.value());
Eric Holk3cc4afc2018-11-08 14:16:20 -0800442 } else if (source.is_string()) {
443 constexpr size_t kMaxRegisters = 256;
Eric Holkd1b43832019-01-29 08:32:42 -0800444 CHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
445 CHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
Orion Hodson59d07202019-10-31 15:25:33 +0000446 Encode21c(::dex::Opcode::OP_CONST_STRING, RegisterValue(*instruction.dest()), source.value());
Eric Holkd1b43832019-01-29 08:32:42 -0800447 } else if (source.is_variable()) {
448 // For the moment, we only use this when we need to reshuffle registers for
449 // an invoke instruction, meaning we are too big for the 4-bit version.
450 // We'll err on the side of caution and always generate the 16-bit form of
451 // the instruction.
Orion Hodson59d07202019-10-31 15:25:33 +0000452 auto opcode = instruction.opcode() == Instruction::Op::kMove
453 ? ::dex::Opcode::OP_MOVE_16
454 : ::dex::Opcode::OP_MOVE_OBJECT_16;
Eric Holkd1b43832019-01-29 08:32:42 -0800455 Encode32x(opcode, RegisterValue(*instruction.dest()), RegisterValue(source));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700456 } else {
457 UNIMPLEMENTED(FATAL);
458 }
459}
460
Orion Hodson59d07202019-10-31 15:25:33 +0000461void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::dex::Opcode opcode) {
Eric Holk1c0f3f02018-11-09 13:48:59 -0800462 constexpr size_t kMaxArgs = 5;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700463
Eric Holkd1b43832019-01-29 08:32:42 -0800464 // Currently, we only support up to 5 arguments.
Eric Holk1c0f3f02018-11-09 13:48:59 -0800465 CHECK_LE(instruction.args().size(), kMaxArgs);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700466
Eric Holk1c0f3f02018-11-09 13:48:59 -0800467 uint8_t arguments[kMaxArgs]{};
Eric Holkd1b43832019-01-29 08:32:42 -0800468 bool has_long_args = false;
Eric Holk1c0f3f02018-11-09 13:48:59 -0800469 for (size_t i = 0; i < instruction.args().size(); ++i) {
470 CHECK(instruction.args()[i].is_variable());
471 arguments[i] = RegisterValue(instruction.args()[i]);
Eric Holkd1b43832019-01-29 08:32:42 -0800472 if (!IsShortRegister(arguments[i])) {
473 has_long_args = true;
474 }
Eric Holkb3927582018-11-08 16:40:16 -0800475 }
Eric Holk1c0f3f02018-11-09 13:48:59 -0800476
Eric Holkd1b43832019-01-29 08:32:42 -0800477 if (has_long_args) {
478 // Some of the registers don't fit in the four bit short form of the invoke
479 // instruction, so we need to do an invoke/range. To do this, we need to
480 // first move all the arguments into contiguous temporary registers.
Chih-Hung Hsieh2b61bdd2019-02-05 17:08:30 -0800481 std::array<Value, kMaxArgs> scratch = GetScratchRegisters<kMaxArgs>();
Eric Holkd1b43832019-01-29 08:32:42 -0800482
Eric Holk3092f992019-07-25 15:14:01 -0700483 const auto& prototype = dex_->GetPrototypeByMethodId(instruction.index_argument());
Eric Holkd1b43832019-01-29 08:32:42 -0800484 CHECK(prototype.has_value());
485
486 for (size_t i = 0; i < instruction.args().size(); ++i) {
487 Instruction::Op move_op;
Orion Hodson59d07202019-10-31 15:25:33 +0000488 if (opcode == ::dex::Opcode::OP_INVOKE_VIRTUAL ||
489 opcode == ::dex::Opcode::OP_INVOKE_DIRECT) {
Eric Holkd1b43832019-01-29 08:32:42 -0800490 // In this case, there is an implicit `this` argument, which is always an object.
491 if (i == 0) {
492 move_op = Instruction::Op::kMoveObject;
493 } else {
494 move_op = prototype->ArgType(i - 1).is_object() ? Instruction::Op::kMoveObject
495 : Instruction::Op::kMove;
496 }
497 } else {
498 move_op = prototype->ArgType(i).is_object() ? Instruction::Op::kMoveObject
499 : Instruction::Op::kMove;
500 }
501
502 EncodeMove(Instruction::OpWithArgs(move_op, scratch[i], instruction.args()[i]));
503 }
504
505 Encode3rc(InvokeToInvokeRange(opcode),
506 instruction.args().size(),
Eric Holk3092f992019-07-25 15:14:01 -0700507 instruction.index_argument(),
Eric Holkd1b43832019-01-29 08:32:42 -0800508 RegisterValue(scratch[0]));
509 } else {
510 Encode35c(opcode,
511 instruction.args().size(),
Eric Holk3092f992019-07-25 15:14:01 -0700512 instruction.index_argument(),
Eric Holkd1b43832019-01-29 08:32:42 -0800513 arguments[0],
514 arguments[1],
515 arguments[2],
516 arguments[3],
517 arguments[4]);
518 }
Eric Holkb3927582018-11-08 16:40:16 -0800519
520 // If there is a return value, add a move-result instruction
Eric Holkfaefd4f2018-10-11 16:25:57 -0700521 if (instruction.dest().has_value()) {
Orion Hodson59d07202019-10-31 15:25:33 +0000522 Encode11x(instruction.result_is_object() ? ::dex::Opcode::OP_MOVE_RESULT_OBJECT
523 : ::dex::Opcode::OP_MOVE_RESULT,
Eric Holkc69449d2018-12-13 11:35:58 -0800524 RegisterValue(*instruction.dest()));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700525 }
Eric Holkb3927582018-11-08 16:40:16 -0800526
527 max_args_ = std::max(max_args_, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700528}
529
Eric Holkd62c5aa2018-11-01 15:50:24 -0700530// Encodes a conditional branch that tests a single argument.
Orion Hodson59d07202019-10-31 15:25:33 +0000531void MethodBuilder::EncodeBranch(::dex::Opcode op, const Instruction& instruction) {
Eric Holkd62c5aa2018-11-01 15:50:24 -0700532 const auto& args = instruction.args();
533 const auto& test_value = args[0];
534 const auto& branch_target = args[1];
535 CHECK_EQ(2, args.size());
536 CHECK(test_value.is_variable());
537 CHECK(branch_target.is_label());
538
539 size_t instruction_offset = buffer_.size();
Eric Holk1c0f3f02018-11-09 13:48:59 -0800540 size_t field_offset = buffer_.size() + 1;
541 Encode21c(
542 op, RegisterValue(test_value), LabelValue(branch_target, instruction_offset, field_offset));
Eric Holkd62c5aa2018-11-01 15:50:24 -0700543}
544
Eric Holkb3927582018-11-08 16:40:16 -0800545void MethodBuilder::EncodeNew(const Instruction& instruction) {
Eric Holkd1b43832019-01-29 08:32:42 -0800546 CHECK_EQ(Instruction::Op::kNew, instruction.opcode());
547 CHECK(instruction.dest().has_value());
548 CHECK(instruction.dest()->is_variable());
549 CHECK_EQ(1, instruction.args().size());
Eric Holkb3927582018-11-08 16:40:16 -0800550
551 const Value& type = instruction.args()[0];
Eric Holkd1b43832019-01-29 08:32:42 -0800552 CHECK_LT(RegisterValue(*instruction.dest()), 256);
553 CHECK(type.is_type());
Orion Hodson59d07202019-10-31 15:25:33 +0000554 Encode21c(::dex::Opcode::OP_NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
Eric Holkb3927582018-11-08 16:40:16 -0800555}
556
Eric Holk44d8cdf2018-12-17 13:35:34 -0800557void MethodBuilder::EncodeCast(const Instruction& instruction) {
Eric Holkd1b43832019-01-29 08:32:42 -0800558 CHECK_EQ(Instruction::Op::kCheckCast, instruction.opcode());
559 CHECK(instruction.dest().has_value());
560 CHECK(instruction.dest()->is_variable());
561 CHECK_EQ(1, instruction.args().size());
Eric Holk44d8cdf2018-12-17 13:35:34 -0800562
563 const Value& type = instruction.args()[0];
Eric Holkd1b43832019-01-29 08:32:42 -0800564 CHECK_LT(RegisterValue(*instruction.dest()), 256);
565 CHECK(type.is_type());
Orion Hodson59d07202019-10-31 15:25:33 +0000566 Encode21c(::dex::Opcode::OP_CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
Eric Holk44d8cdf2018-12-17 13:35:34 -0800567}
568
Eric Holkf3b95892019-07-30 14:47:06 -0700569void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
570 const auto& args = instruction.args();
Eric Holk70445d02019-07-26 09:37:46 -0700571 switch (instruction.opcode()) {
572 case Instruction::Op::kGetStaticField: {
573 CHECK(instruction.dest().has_value());
574 CHECK(instruction.dest()->is_variable());
575 CHECK_EQ(0, instruction.args().size());
Eric Holk3092f992019-07-25 15:14:01 -0700576
Orion Hodson59d07202019-10-31 15:25:33 +0000577 Encode21c(::dex::Opcode::OP_SGET,
Eric Holk70445d02019-07-26 09:37:46 -0700578 RegisterValue(*instruction.dest()),
579 instruction.index_argument());
580 break;
581 }
582 case Instruction::Op::kSetStaticField: {
583 CHECK(!instruction.dest().has_value());
Eric Holk70445d02019-07-26 09:37:46 -0700584 CHECK_EQ(1, args.size());
585 CHECK(args[0].is_variable());
586
Orion Hodson59d07202019-10-31 15:25:33 +0000587 Encode21c(::dex::Opcode::OP_SPUT, RegisterValue(args[0]), instruction.index_argument());
Eric Holkf3b95892019-07-30 14:47:06 -0700588 break;
589 }
590 case Instruction::Op::kGetInstanceField: {
591 CHECK(instruction.dest().has_value());
592 CHECK(instruction.dest()->is_variable());
593 CHECK_EQ(1, instruction.args().size());
594
Orion Hodson59d07202019-10-31 15:25:33 +0000595 Encode22c(::dex::Opcode::OP_IGET,
Eric Holkf3b95892019-07-30 14:47:06 -0700596 RegisterValue(*instruction.dest()),
Eric Holk70445d02019-07-26 09:37:46 -0700597 RegisterValue(args[0]),
598 instruction.index_argument());
599 break;
600 }
Eric Holkf3b95892019-07-30 14:47:06 -0700601 case Instruction::Op::kSetInstanceField: {
602 CHECK(!instruction.dest().has_value());
603 CHECK_EQ(2, args.size());
604 CHECK(args[0].is_variable());
605 CHECK(args[1].is_variable());
606
Orion Hodson59d07202019-10-31 15:25:33 +0000607 Encode22c(::dex::Opcode::OP_IPUT,
Eric Holkf3b95892019-07-30 14:47:06 -0700608 RegisterValue(args[1]),
609 RegisterValue(args[0]),
610 instruction.index_argument());
611 break;
Eric Holk70445d02019-07-26 09:37:46 -0700612 }
Eric Holkf3b95892019-07-30 14:47:06 -0700613 default: { LOG(FATAL) << "Unsupported field operation"; }
Eric Holk70445d02019-07-26 09:37:46 -0700614 }
Eric Holk3092f992019-07-25 15:14:01 -0700615}
616
Eric Holkd62c5aa2018-11-01 15:50:24 -0700617size_t MethodBuilder::RegisterValue(const Value& value) const {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700618 if (value.is_register()) {
619 return value.value();
620 } else if (value.is_parameter()) {
Eric Holk5c6a1a52019-09-17 13:28:34 -0700621 return value.value() + NumRegisters() + kMaxScratchRegisters;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700622 }
Eric Holkd1b43832019-01-29 08:32:42 -0800623 CHECK(false && "Must be either a parameter or a register");
Eric Holkfaefd4f2018-10-11 16:25:57 -0700624 return 0;
625}
626
Eric Holkd62c5aa2018-11-01 15:50:24 -0700627void MethodBuilder::BindLabel(const Value& label_id) {
628 CHECK(label_id.is_label());
629
630 LabelData& label = labels_[label_id.value()];
631 CHECK(!label.bound_address.has_value());
632
633 label.bound_address = buffer_.size();
634
635 // patch any forward references to this label.
636 for (const auto& ref : label.references) {
637 buffer_[ref.field_offset] = *label.bound_address - ref.instruction_offset;
638 }
639 // No point keeping these around anymore.
640 label.references.clear();
641}
642
643::dex::u2 MethodBuilder::LabelValue(const Value& label_id, size_t instruction_offset,
644 size_t field_offset) {
645 CHECK(label_id.is_label());
646 LabelData& label = labels_[label_id.value()];
647
648 // Short-circuit if the label is already bound.
649 if (label.bound_address.has_value()) {
650 return *label.bound_address - instruction_offset;
651 }
652
653 // Otherwise, save a reference to where we need to back-patch later.
654 label.references.push_front(LabelReference{instruction_offset, field_offset});
655 return 0;
656}
657
Eric Holkfaefd4f2018-10-11 16:25:57 -0700658const MethodDeclData& DexBuilder::GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
659 Prototype prototype) {
660 MethodDeclData& entry = method_id_map_[{type, name, prototype}];
661
662 if (entry.decl == nullptr) {
663 // This method has not already been declared, so declare it.
664 ir::MethodDecl* decl = dex_file_->Alloc<ir::MethodDecl>();
665 // The method id is the last added method.
666 size_t id = dex_file_->methods.size() - 1;
667
668 ir::String* dex_name{GetOrAddString(name)};
669 decl->name = dex_name;
670 decl->parent = GetOrAddType(type.descriptor());
671 decl->prototype = GetOrEncodeProto(prototype);
672
673 // update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc)
674 auto new_index = dex_file_->methods_indexes.AllocateIndex();
675 auto& ir_node = dex_file_->methods_map[new_index];
Eric Holkd1b43832019-01-29 08:32:42 -0800676 CHECK(ir_node == nullptr);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700677 ir_node = decl;
Eric Holkc69449d2018-12-13 11:35:58 -0800678 decl->orig_index = decl->index = new_index;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700679
680 entry = {id, decl};
681 }
682
683 return entry;
684}
685
Eric Holkd1b43832019-01-29 08:32:42 -0800686std::optional<const Prototype> DexBuilder::GetPrototypeByMethodId(size_t method_id) const {
687 for (const auto& entry : method_id_map_) {
688 if (entry.second.id == method_id) {
689 return entry.first.prototype;
690 }
691 }
692 return {};
693}
694
Eric Holkfaefd4f2018-10-11 16:25:57 -0700695ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) {
696 ir::Proto*& ir_proto = proto_map_[prototype];
697 if (ir_proto == nullptr) {
698 ir_proto = prototype.Encode(this);
699 }
700 return ir_proto;
Eric Holkdbc36e22018-09-20 12:03:10 -0700701}
702
703} // namespace dex
704} // namespace startop