blob: 94879d0bbcc42e8cf726e603f58a74668af1176a [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
Eric Holkfaefd4f2018-10-11 16:25:57 -070024#define DCHECK_NOT_NULL(p) DCHECK((p) != nullptr)
25
Eric Holkdbc36e22018-09-20 12:03:10 -070026namespace startop {
27namespace dex {
28
29using std::shared_ptr;
30using std::string;
31
Eric Holkdbc36e22018-09-20 12:03:10 -070032using ::dex::kAccPublic;
Eric Holkfaefd4f2018-10-11 16:25:57 -070033using Op = Instruction::Op;
Eric Holkdbc36e22018-09-20 12:03:10 -070034
35const 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
45} // namespace
46
Eric Holkfaefd4f2018-10-11 16:25:57 -070047std::ostream& operator<<(std::ostream& out, const Instruction::Op& opcode) {
48 switch (opcode) {
49 case Instruction::Op::kReturn:
50 out << "kReturn";
51 return out;
Eric Holk3cc4afc2018-11-08 14:16:20 -080052 case Instruction::Op::kReturnObject:
53 out << "kReturnObject";
54 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -070055 case Instruction::Op::kMove:
56 out << "kMove";
57 return out;
58 case Instruction::Op::kInvokeVirtual:
59 out << "kInvokeVirtual";
60 return out;
Eric Holkb3927582018-11-08 16:40:16 -080061 case Instruction::Op::kInvokeDirect:
62 out << "kInvokeDirect";
63 return out;
Eric Holkc69449d2018-12-13 11:35:58 -080064 case Instruction::Op::kInvokeStatic:
65 out << "kInvokeStatic";
66 return out;
67 case Instruction::Op::kInvokeInterface:
68 out << "kInvokeInterface";
69 return out;
Eric Holkd62c5aa2018-11-01 15:50:24 -070070 case Instruction::Op::kBindLabel:
71 out << "kBindLabel";
72 return out;
73 case Instruction::Op::kBranchEqz:
74 out << "kBranchEqz";
75 return out;
Eric Holkc69449d2018-12-13 11:35:58 -080076 case Instruction::Op::kBranchNEqz:
77 out << "kBranchNEqz";
78 return out;
Eric Holkb3927582018-11-08 16:40:16 -080079 case Instruction::Op::kNew:
80 out << "kNew";
81 return out;
Eric Holkfaefd4f2018-10-11 16:25:57 -070082 }
83}
84
Eric Holkc69449d2018-12-13 11:35:58 -080085std::ostream& operator<<(std::ostream& out, const Value& value) {
86 if (value.is_register()) {
87 out << "Register(" << value.value() << ")";
88 } else if (value.is_parameter()) {
89 out << "Parameter(" << value.value() << ")";
90 } else if (value.is_immediate()) {
91 out << "Immediate(" << value.value() << ")";
92 } else if (value.is_string()) {
93 out << "String(" << value.value() << ")";
94 } else if (value.is_label()) {
95 out << "Label(" << value.value() << ")";
96 } else if (value.is_type()) {
97 out << "Type(" << value.value() << ")";
98 } else {
99 out << "UnknownValue";
100 }
101 return out;
102}
103
Eric Holkdbc36e22018-09-20 12:03:10 -0700104void* TrackingAllocator::Allocate(size_t size) {
105 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(size);
106 void* raw_buffer = buffer.get();
107 allocations_[raw_buffer] = std::move(buffer);
108 return raw_buffer;
109}
110
111void TrackingAllocator::Free(void* ptr) { allocations_.erase(allocations_.find(ptr)); }
112
113// Write out a DEX file that is basically:
114//
115// package dextest;
116// public class DexTest {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700117// public static int foo(String s) { return s.length(); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700118// }
119void WriteTestDexFile(const string& filename) {
120 DexBuilder dex_file;
121
122 ClassBuilder cbuilder{dex_file.MakeClass("dextest.DexTest")};
123 cbuilder.set_source_file("dextest.java");
124
Eric Holkfaefd4f2018-10-11 16:25:57 -0700125 TypeDescriptor string_type = TypeDescriptor::FromClassname("java.lang.String");
Eric Holkdbc36e22018-09-20 12:03:10 -0700126
Eric Holkfaefd4f2018-10-11 16:25:57 -0700127 MethodBuilder method{cbuilder.CreateMethod("foo", Prototype{TypeDescriptor::Int(), string_type})};
128
129 Value result = method.MakeRegister();
130
131 MethodDeclData string_length =
132 dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()});
133
134 method.AddInstruction(Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0)));
135 method.BuildReturn(result);
Eric Holkdbc36e22018-09-20 12:03:10 -0700136
137 method.Encode();
138
139 slicer::MemView image{dex_file.CreateImage()};
140
141 std::ofstream out_file(filename);
142 out_file.write(image.ptr<const char>(), image.size());
143}
144
Eric Holkfaefd4f2018-10-11 16:25:57 -0700145TypeDescriptor TypeDescriptor::FromClassname(const std::string& name) {
146 return TypeDescriptor{art::DotToDescriptor(name.c_str())};
147}
148
Eric Holkdbc36e22018-09-20 12:03:10 -0700149DexBuilder::DexBuilder() : dex_file_{std::make_shared<ir::DexFile>()} {
150 dex_file_->magic = slicer::MemView{kDexFileMagic, sizeof(kDexFileMagic)};
151}
152
153slicer::MemView DexBuilder::CreateImage() {
154 ::dex::Writer writer(dex_file_);
155 size_t image_size{0};
156 ::dex::u1* image = writer.CreateImage(&allocator_, &image_size);
157 return slicer::MemView{image, image_size};
158}
159
160ir::String* DexBuilder::GetOrAddString(const std::string& string) {
161 ir::String*& entry = strings_[string];
162
163 if (entry == nullptr) {
164 // Need to encode the length and then write out the bytes, including 1 byte for null terminator
165 auto buffer = std::make_unique<uint8_t[]>(string.size() + kMaxEncodedStringLength + 1);
166 uint8_t* string_data_start = ::dex::WriteULeb128(buffer.get(), string.size());
167
168 size_t header_length =
169 reinterpret_cast<uintptr_t>(string_data_start) - reinterpret_cast<uintptr_t>(buffer.get());
170
171 auto end = std::copy(string.begin(), string.end(), string_data_start);
172 *end = '\0';
173
174 entry = Alloc<ir::String>();
175 // +1 for null terminator
176 entry->data = slicer::MemView{buffer.get(), header_length + string.size() + 1};
Eric Holk3cc4afc2018-11-08 14:16:20 -0800177 ::dex::u4 const new_index = dex_file_->strings_indexes.AllocateIndex();
178 dex_file_->strings_map[new_index] = entry;
179 entry->orig_index = new_index;
Eric Holkdbc36e22018-09-20 12:03:10 -0700180 string_data_.push_back(std::move(buffer));
181 }
182 return entry;
183}
184
185ClassBuilder DexBuilder::MakeClass(const std::string& name) {
186 auto* class_def = Alloc<ir::Class>();
187 ir::Type* type_def = GetOrAddType(art::DotToDescriptor(name.c_str()));
188 type_def->class_def = class_def;
189
190 class_def->type = type_def;
191 class_def->super_class = GetOrAddType(art::DotToDescriptor("java.lang.Object"));
192 class_def->access_flags = kAccPublic;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700193 return ClassBuilder{this, name, class_def};
Eric Holkdbc36e22018-09-20 12:03:10 -0700194}
195
Eric Holkdbc36e22018-09-20 12:03:10 -0700196ir::Type* DexBuilder::GetOrAddType(const std::string& descriptor) {
197 if (types_by_descriptor_.find(descriptor) != types_by_descriptor_.end()) {
198 return types_by_descriptor_[descriptor];
199 }
200
201 ir::Type* type = Alloc<ir::Type>();
202 type->descriptor = GetOrAddString(descriptor);
203 types_by_descriptor_[descriptor] = type;
Eric Holkb3927582018-11-08 16:40:16 -0800204 type->orig_index = dex_file_->types_indexes.AllocateIndex();
205 dex_file_->types_map[type->orig_index] = type;
Eric Holkdbc36e22018-09-20 12:03:10 -0700206 return type;
207}
208
209ir::Proto* Prototype::Encode(DexBuilder* dex) const {
210 auto* proto = dex->Alloc<ir::Proto>();
211 proto->shorty = dex->GetOrAddString(Shorty());
212 proto->return_type = dex->GetOrAddType(return_type_.descriptor());
213 if (param_types_.size() > 0) {
214 proto->param_types = dex->Alloc<ir::TypeList>();
215 for (const auto& param_type : param_types_) {
216 proto->param_types->types.push_back(dex->GetOrAddType(param_type.descriptor()));
217 }
218 } else {
219 proto->param_types = nullptr;
220 }
221 return proto;
222}
223
224std::string Prototype::Shorty() const {
225 std::string shorty;
226 shorty.append(return_type_.short_descriptor());
227 for (const auto& type_descriptor : param_types_) {
228 shorty.append(type_descriptor.short_descriptor());
229 }
230 return shorty;
231}
232
Eric Holkfaefd4f2018-10-11 16:25:57 -0700233ClassBuilder::ClassBuilder(DexBuilder* parent, const std::string& name, ir::Class* class_def)
234 : parent_(parent), type_descriptor_{TypeDescriptor::FromClassname(name)}, class_(class_def) {}
Eric Holkdbc36e22018-09-20 12:03:10 -0700235
236MethodBuilder ClassBuilder::CreateMethod(const std::string& name, Prototype prototype) {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700237 ir::MethodDecl* decl = parent_->GetOrDeclareMethod(type_descriptor_, name, prototype).decl;
Eric Holkdbc36e22018-09-20 12:03:10 -0700238
239 return MethodBuilder{parent_, class_, decl};
240}
241
242void ClassBuilder::set_source_file(const string& source) {
243 class_->source_file = parent_->GetOrAddString(source);
244}
245
246MethodBuilder::MethodBuilder(DexBuilder* dex, ir::Class* class_def, ir::MethodDecl* decl)
247 : dex_{dex}, class_{class_def}, decl_{decl} {}
248
249ir::EncodedMethod* MethodBuilder::Encode() {
250 auto* method = dex_->Alloc<ir::EncodedMethod>();
251 method->decl = decl_;
252
253 // TODO: make access flags configurable
254 method->access_flags = kAccPublic | ::dex::kAccStatic;
255
256 auto* code = dex_->Alloc<ir::Code>();
Eric Holkfaefd4f2018-10-11 16:25:57 -0700257 DCHECK_NOT_NULL(decl_->prototype);
258 size_t const num_args =
259 decl_->prototype->param_types != nullptr ? decl_->prototype->param_types->types.size() : 0;
260 code->registers = num_registers_ + num_args;
261 code->ins_count = num_args;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700262 EncodeInstructions();
Eric Holkdbc36e22018-09-20 12:03:10 -0700263 code->instructions = slicer::ArrayView<const ::dex::u2>(buffer_.data(), buffer_.size());
Eric Holkb3927582018-11-08 16:40:16 -0800264 size_t const return_count = decl_->prototype->return_type == dex_->GetOrAddType("V") ? 0 : 1;
265 code->outs_count = std::max(return_count, max_args_);
Eric Holkdbc36e22018-09-20 12:03:10 -0700266 method->code = code;
267
268 class_->direct_methods.push_back(method);
269
270 return method;
271}
272
Eric Holkfaefd4f2018-10-11 16:25:57 -0700273Value MethodBuilder::MakeRegister() { return Value::Local(num_registers_++); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700274
Eric Holkd62c5aa2018-11-01 15:50:24 -0700275Value MethodBuilder::MakeLabel() {
276 labels_.push_back({});
277 return Value::Label(labels_.size() - 1);
278}
279
Eric Holkfaefd4f2018-10-11 16:25:57 -0700280void MethodBuilder::AddInstruction(Instruction instruction) {
281 instructions_.push_back(instruction);
282}
Eric Holkdbc36e22018-09-20 12:03:10 -0700283
Eric Holkfaefd4f2018-10-11 16:25:57 -0700284void MethodBuilder::BuildReturn() { AddInstruction(Instruction::OpNoArgs(Op::kReturn)); }
Eric Holkdbc36e22018-09-20 12:03:10 -0700285
Eric Holk3cc4afc2018-11-08 14:16:20 -0800286void MethodBuilder::BuildReturn(Value src, bool is_object) {
287 AddInstruction(Instruction::OpWithArgs(
288 is_object ? Op::kReturnObject : Op::kReturn, /*destination=*/{}, src));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700289}
290
291void MethodBuilder::BuildConst4(Value target, int value) {
Eric Holkdbc36e22018-09-20 12:03:10 -0700292 DCHECK_LT(value, 16);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700293 AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::Immediate(value)));
294}
295
Eric Holk3cc4afc2018-11-08 14:16:20 -0800296void MethodBuilder::BuildConstString(Value target, const std::string& value) {
297 const ir::String* const dex_string = dex_->GetOrAddString(value);
298 AddInstruction(Instruction::OpWithArgs(Op::kMove, target, Value::String(dex_string->orig_index)));
299}
300
Eric Holkfaefd4f2018-10-11 16:25:57 -0700301void MethodBuilder::EncodeInstructions() {
302 buffer_.clear();
303 for (const auto& instruction : instructions_) {
304 EncodeInstruction(instruction);
305 }
306}
307
308void MethodBuilder::EncodeInstruction(const Instruction& instruction) {
309 switch (instruction.opcode()) {
310 case Instruction::Op::kReturn:
Eric Holk3cc4afc2018-11-08 14:16:20 -0800311 return EncodeReturn(instruction, ::art::Instruction::RETURN);
312 case Instruction::Op::kReturnObject:
313 return EncodeReturn(instruction, ::art::Instruction::RETURN_OBJECT);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700314 case Instruction::Op::kMove:
315 return EncodeMove(instruction);
316 case Instruction::Op::kInvokeVirtual:
Eric Holkb3927582018-11-08 16:40:16 -0800317 return EncodeInvoke(instruction, art::Instruction::INVOKE_VIRTUAL);
318 case Instruction::Op::kInvokeDirect:
319 return EncodeInvoke(instruction, art::Instruction::INVOKE_DIRECT);
Eric Holkc69449d2018-12-13 11:35:58 -0800320 case Instruction::Op::kInvokeStatic:
321 return EncodeInvoke(instruction, art::Instruction::INVOKE_STATIC);
322 case Instruction::Op::kInvokeInterface:
323 return EncodeInvoke(instruction, art::Instruction::INVOKE_INTERFACE);
Eric Holkd62c5aa2018-11-01 15:50:24 -0700324 case Instruction::Op::kBindLabel:
325 return BindLabel(instruction.args()[0]);
326 case Instruction::Op::kBranchEqz:
327 return EncodeBranch(art::Instruction::IF_EQZ, instruction);
Eric Holkc69449d2018-12-13 11:35:58 -0800328 case Instruction::Op::kBranchNEqz:
329 return EncodeBranch(art::Instruction::IF_NEZ, instruction);
Eric Holkb3927582018-11-08 16:40:16 -0800330 case Instruction::Op::kNew:
331 return EncodeNew(instruction);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700332 }
333}
334
Eric Holk3cc4afc2018-11-08 14:16:20 -0800335void MethodBuilder::EncodeReturn(const Instruction& instruction, ::art::Instruction::Code opcode) {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700336 DCHECK(!instruction.dest().has_value());
337 if (instruction.args().size() == 0) {
Eric Holk1c0f3f02018-11-09 13:48:59 -0800338 Encode10x(art::Instruction::RETURN_VOID);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700339 } else {
Eric Holk3cc4afc2018-11-08 14:16:20 -0800340 DCHECK_EQ(1, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700341 size_t source = RegisterValue(instruction.args()[0]);
Eric Holk1c0f3f02018-11-09 13:48:59 -0800342 Encode11x(opcode, source);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700343 }
344}
345
346void MethodBuilder::EncodeMove(const Instruction& instruction) {
347 DCHECK_EQ(Instruction::Op::kMove, instruction.opcode());
348 DCHECK(instruction.dest().has_value());
349 DCHECK(instruction.dest()->is_register() || instruction.dest()->is_parameter());
350 DCHECK_EQ(1, instruction.args().size());
351
352 const Value& source = instruction.args()[0];
353
354 if (source.is_immediate()) {
355 // TODO: support more registers
356 DCHECK_LT(RegisterValue(*instruction.dest()), 16);
Eric Holk1c0f3f02018-11-09 13:48:59 -0800357 Encode11n(art::Instruction::CONST_4, RegisterValue(*instruction.dest()), source.value());
Eric Holk3cc4afc2018-11-08 14:16:20 -0800358 } else if (source.is_string()) {
359 constexpr size_t kMaxRegisters = 256;
360 DCHECK_LT(RegisterValue(*instruction.dest()), kMaxRegisters);
361 DCHECK_LT(source.value(), 65536); // make sure we don't need a jumbo string
Eric Holk1c0f3f02018-11-09 13:48:59 -0800362 Encode21c(::art::Instruction::CONST_STRING, RegisterValue(*instruction.dest()), source.value());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700363 } else {
364 UNIMPLEMENTED(FATAL);
365 }
366}
367
Eric Holkb3927582018-11-08 16:40:16 -0800368void MethodBuilder::EncodeInvoke(const Instruction& instruction, ::art::Instruction::Code opcode) {
Eric Holk1c0f3f02018-11-09 13:48:59 -0800369 constexpr size_t kMaxArgs = 5;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700370
Eric Holk1c0f3f02018-11-09 13:48:59 -0800371 CHECK_LE(instruction.args().size(), kMaxArgs);
Eric Holkfaefd4f2018-10-11 16:25:57 -0700372
Eric Holk1c0f3f02018-11-09 13:48:59 -0800373 uint8_t arguments[kMaxArgs]{};
374 for (size_t i = 0; i < instruction.args().size(); ++i) {
375 CHECK(instruction.args()[i].is_variable());
376 arguments[i] = RegisterValue(instruction.args()[i]);
Eric Holkb3927582018-11-08 16:40:16 -0800377 }
Eric Holk1c0f3f02018-11-09 13:48:59 -0800378
379 Encode35c(opcode,
380 instruction.args().size(),
381 instruction.method_id(),
382 arguments[0],
383 arguments[1],
384 arguments[2],
385 arguments[3],
386 arguments[4]);
Eric Holkb3927582018-11-08 16:40:16 -0800387
388 // If there is a return value, add a move-result instruction
Eric Holkfaefd4f2018-10-11 16:25:57 -0700389 if (instruction.dest().has_value()) {
Eric Holkc69449d2018-12-13 11:35:58 -0800390 Encode11x(instruction.result_is_object() ? art::Instruction::MOVE_RESULT_OBJECT
391 : art::Instruction::MOVE_RESULT,
392 RegisterValue(*instruction.dest()));
Eric Holkfaefd4f2018-10-11 16:25:57 -0700393 }
Eric Holkb3927582018-11-08 16:40:16 -0800394
395 max_args_ = std::max(max_args_, instruction.args().size());
Eric Holkfaefd4f2018-10-11 16:25:57 -0700396}
397
Eric Holkd62c5aa2018-11-01 15:50:24 -0700398// Encodes a conditional branch that tests a single argument.
399void MethodBuilder::EncodeBranch(art::Instruction::Code op, const Instruction& instruction) {
400 const auto& args = instruction.args();
401 const auto& test_value = args[0];
402 const auto& branch_target = args[1];
403 CHECK_EQ(2, args.size());
404 CHECK(test_value.is_variable());
405 CHECK(branch_target.is_label());
406
407 size_t instruction_offset = buffer_.size();
Eric Holk1c0f3f02018-11-09 13:48:59 -0800408 size_t field_offset = buffer_.size() + 1;
409 Encode21c(
410 op, RegisterValue(test_value), LabelValue(branch_target, instruction_offset, field_offset));
Eric Holkd62c5aa2018-11-01 15:50:24 -0700411}
412
Eric Holkb3927582018-11-08 16:40:16 -0800413void MethodBuilder::EncodeNew(const Instruction& instruction) {
414 DCHECK_EQ(Instruction::Op::kNew, instruction.opcode());
415 DCHECK(instruction.dest().has_value());
416 DCHECK(instruction.dest()->is_variable());
417 DCHECK_EQ(1, instruction.args().size());
418
419 const Value& type = instruction.args()[0];
420 DCHECK_LT(RegisterValue(*instruction.dest()), 256);
421 DCHECK(type.is_type());
Eric Holk1c0f3f02018-11-09 13:48:59 -0800422 Encode21c(::art::Instruction::NEW_INSTANCE, RegisterValue(*instruction.dest()), type.value());
Eric Holkb3927582018-11-08 16:40:16 -0800423}
424
Eric Holkd62c5aa2018-11-01 15:50:24 -0700425size_t MethodBuilder::RegisterValue(const Value& value) const {
Eric Holkfaefd4f2018-10-11 16:25:57 -0700426 if (value.is_register()) {
427 return value.value();
428 } else if (value.is_parameter()) {
429 return value.value() + num_registers_;
430 }
431 DCHECK(false && "Must be either a parameter or a register");
432 return 0;
433}
434
Eric Holkd62c5aa2018-11-01 15:50:24 -0700435void MethodBuilder::BindLabel(const Value& label_id) {
436 CHECK(label_id.is_label());
437
438 LabelData& label = labels_[label_id.value()];
439 CHECK(!label.bound_address.has_value());
440
441 label.bound_address = buffer_.size();
442
443 // patch any forward references to this label.
444 for (const auto& ref : label.references) {
445 buffer_[ref.field_offset] = *label.bound_address - ref.instruction_offset;
446 }
447 // No point keeping these around anymore.
448 label.references.clear();
449}
450
451::dex::u2 MethodBuilder::LabelValue(const Value& label_id, size_t instruction_offset,
452 size_t field_offset) {
453 CHECK(label_id.is_label());
454 LabelData& label = labels_[label_id.value()];
455
456 // Short-circuit if the label is already bound.
457 if (label.bound_address.has_value()) {
458 return *label.bound_address - instruction_offset;
459 }
460
461 // Otherwise, save a reference to where we need to back-patch later.
462 label.references.push_front(LabelReference{instruction_offset, field_offset});
463 return 0;
464}
465
Eric Holkfaefd4f2018-10-11 16:25:57 -0700466const MethodDeclData& DexBuilder::GetOrDeclareMethod(TypeDescriptor type, const std::string& name,
467 Prototype prototype) {
468 MethodDeclData& entry = method_id_map_[{type, name, prototype}];
469
470 if (entry.decl == nullptr) {
471 // This method has not already been declared, so declare it.
472 ir::MethodDecl* decl = dex_file_->Alloc<ir::MethodDecl>();
473 // The method id is the last added method.
474 size_t id = dex_file_->methods.size() - 1;
475
476 ir::String* dex_name{GetOrAddString(name)};
477 decl->name = dex_name;
478 decl->parent = GetOrAddType(type.descriptor());
479 decl->prototype = GetOrEncodeProto(prototype);
480
481 // update the index -> ir node map (see tools/dexter/slicer/dex_ir_builder.cc)
482 auto new_index = dex_file_->methods_indexes.AllocateIndex();
483 auto& ir_node = dex_file_->methods_map[new_index];
484 SLICER_CHECK(ir_node == nullptr);
485 ir_node = decl;
Eric Holkc69449d2018-12-13 11:35:58 -0800486 decl->orig_index = decl->index = new_index;
Eric Holkfaefd4f2018-10-11 16:25:57 -0700487
488 entry = {id, decl};
489 }
490
491 return entry;
492}
493
494ir::Proto* DexBuilder::GetOrEncodeProto(Prototype prototype) {
495 ir::Proto*& ir_proto = proto_map_[prototype];
496 if (ir_proto == nullptr) {
497 ir_proto = prototype.Encode(this);
498 }
499 return ir_proto;
Eric Holkdbc36e22018-09-20 12:03:10 -0700500}
501
502} // namespace dex
503} // namespace startop