blob: beccf01872c856de8818d889844ee27476d23eb2 [file] [log] [blame]
Nicolas Geoffray818f2102014-02-18 16:43:35 +00001/*
2 *
3 * Copyright (C) 2014 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000018#include "dex_file.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000019#include "dex_file-inl.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000020#include "dex_instruction.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000021#include "dex_instruction-inl.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000022#include "builder.h"
23#include "nodes.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000024#include "primitive.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000025
26namespace art {
27
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010028void HGraphBuilder::InitializeLocals(uint16_t count) {
29 graph_->SetNumberOfVRegs(count);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000030 locals_.SetSize(count);
31 for (int i = 0; i < count; i++) {
32 HLocal* local = new (arena_) HLocal(i);
33 entry_block_->AddInstruction(local);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000034 locals_.Put(i, local);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000035 }
36}
37
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010038bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
39 // dex_compilation_unit_ is null only when unit testing.
40 if (dex_compilation_unit_ == nullptr) {
41 return true;
42 }
43
44 graph_->SetNumberOfInVRegs(number_of_parameters);
45 const char* shorty = dex_compilation_unit_->GetShorty();
46 int locals_index = locals_.Size() - number_of_parameters;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010047 int parameter_index = 0;
48
49 if (!dex_compilation_unit_->IsStatic()) {
50 // Add the implicit 'this' argument, not expressed in the signature.
51 HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010052 entry_block_->AddInstruction(parameter);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010053 HLocal* local = GetLocalAt(locals_index++);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010054 entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010055 number_of_parameters--;
56 }
57
58 uint32_t pos = 1;
59 for (int i = 0; i < number_of_parameters; i++) {
60 switch (shorty[pos++]) {
61 case 'F':
62 case 'D':
63 case 'J': {
64 return false;
65 }
66
67 default: {
68 // integer and reference parameters.
69 HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010070 entry_block_->AddInstruction(parameter);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010071 HLocal* local = GetLocalAt(locals_index++);
72 // Store the parameter value in the local that the dex code will use
73 // to reference that parameter.
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010074 entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010075 break;
76 }
77 }
78 }
79 return true;
80}
81
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000082static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000083 if (code_item.tries_size_ > 0) {
84 return false;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000085 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000086 return true;
87}
88
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010089template<typename T>
90void HGraphBuilder::If_22t(const Instruction& instruction, int32_t dex_offset, bool is_not) {
91 HInstruction* first = LoadLocal(instruction.VRegA());
92 HInstruction* second = LoadLocal(instruction.VRegB());
93 current_block_->AddInstruction(new (arena_) T(first, second));
94 if (is_not) {
95 current_block_->AddInstruction(new (arena_) HNot(current_block_->GetLastInstruction()));
96 }
97 current_block_->AddInstruction(new (arena_) HIf(current_block_->GetLastInstruction()));
98 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
99 DCHECK(target != nullptr);
100 current_block_->AddSuccessor(target);
101 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
102 DCHECK(target != nullptr);
103 current_block_->AddSuccessor(target);
104 current_block_ = nullptr;
105}
106
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000107HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000108 if (!CanHandleCodeItem(code_item)) {
109 return nullptr;
110 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000111
112 const uint16_t* code_ptr = code_item.insns_;
113 const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
114
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000115 // Setup the graph with the entry block and exit block.
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000116 graph_ = new (arena_) HGraph(arena_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000117 entry_block_ = new (arena_) HBasicBlock(graph_);
118 graph_->AddBlock(entry_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000119 exit_block_ = new (arena_) HBasicBlock(graph_);
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000120 graph_->SetEntryBlock(entry_block_);
121 graph_->SetExitBlock(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000122
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000123 InitializeLocals(code_item.registers_size_);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100124 graph_->UpdateMaximumNumberOfOutVRegs(code_item.outs_size_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000125
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000126 // To avoid splitting blocks, we compute ahead of time the instructions that
127 // start a new block, and create these blocks.
128 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000129
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100130 if (!InitializeParameters(code_item.ins_size_)) {
131 return nullptr;
132 }
133
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000134 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000135 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000136 // Update the current block if dex_offset starts a new block.
137 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000138 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000139 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
140 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000141 code_ptr += instruction.SizeInCodeUnits();
142 }
143
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000144 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000145 graph_->AddBlock(exit_block_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000146 exit_block_->AddInstruction(new (arena_) HExit());
147 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000148 return graph_;
149}
150
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000151void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
152 HBasicBlock* block = FindBlockStartingAt(index);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000153 if (block == nullptr) {
154 return;
155 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000156
157 if (current_block_ != nullptr) {
158 // Branching instructions clear current_block, so we know
159 // the last instruction of the current block is not a branching
160 // instruction. We add an unconditional goto to the found block.
161 current_block_->AddInstruction(new (arena_) HGoto());
162 current_block_->AddSuccessor(block);
163 }
164 graph_->AddBlock(block);
165 current_block_ = block;
166}
167
168void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
169 // TODO: Support switch instructions.
170 branch_targets_.SetSize(code_end - code_ptr);
171
172 // Create the first block for the dex instructions, single successor of the entry block.
173 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
174 branch_targets_.Put(0, block);
175 entry_block_->AddSuccessor(block);
176
177 // Iterate over all instructions and find branching instructions. Create blocks for
178 // the locations these instructions branch to.
179 size_t dex_offset = 0;
180 while (code_ptr < code_end) {
181 const Instruction& instruction = *Instruction::At(code_ptr);
182 if (instruction.IsBranch()) {
183 int32_t target = instruction.GetTargetOffset() + dex_offset;
184 // Create a block for the target instruction.
185 if (FindBlockStartingAt(target) == nullptr) {
186 block = new (arena_) HBasicBlock(graph_);
187 branch_targets_.Put(target, block);
188 }
189 dex_offset += instruction.SizeInCodeUnits();
190 code_ptr += instruction.SizeInCodeUnits();
191 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
192 block = new (arena_) HBasicBlock(graph_);
193 branch_targets_.Put(dex_offset, block);
194 }
195 } else {
196 code_ptr += instruction.SizeInCodeUnits();
197 dex_offset += instruction.SizeInCodeUnits();
198 }
199 }
200}
201
202HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
203 DCHECK_GE(index, 0);
204 return branch_targets_.Get(index);
205}
206
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100207template<typename T>
208void HGraphBuilder::Binop_32x(const Instruction& instruction) {
209 HInstruction* first = LoadLocal(instruction.VRegB());
210 HInstruction* second = LoadLocal(instruction.VRegC());
211 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
212 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
213}
214
215template<typename T>
216void HGraphBuilder::Binop_12x(const Instruction& instruction) {
217 HInstruction* first = LoadLocal(instruction.VRegA());
218 HInstruction* second = LoadLocal(instruction.VRegB());
219 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
220 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
221}
222
223template<typename T>
224void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
225 HInstruction* first = LoadLocal(instruction.VRegB());
226 HInstruction* second = GetConstant(instruction.VRegC_22s());
227 if (reverse) {
228 std::swap(first, second);
229 }
230 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
231 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
232}
233
234template<typename T>
235void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
236 HInstruction* first = LoadLocal(instruction.VRegB());
237 HInstruction* second = GetConstant(instruction.VRegC_22b());
238 if (reverse) {
239 std::swap(first, second);
240 }
241 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
242 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
243}
244
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000245bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000246 if (current_block_ == nullptr) {
247 return true; // Dead code
248 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000249
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000250 switch (instruction.Opcode()) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000251 case Instruction::CONST_4: {
252 int32_t register_index = instruction.VRegA();
253 HIntConstant* constant = GetConstant(instruction.VRegB_11n());
254 UpdateLocal(register_index, constant);
255 break;
256 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000257
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100258 case Instruction::CONST_16: {
259 int32_t register_index = instruction.VRegA();
260 HIntConstant* constant = GetConstant(instruction.VRegB_21s());
261 UpdateLocal(register_index, constant);
262 break;
263 }
264
265 case Instruction::MOVE: {
266 HInstruction* value = LoadLocal(instruction.VRegB());
267 UpdateLocal(instruction.VRegA(), value);
268 break;
269 }
270
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000271 case Instruction::RETURN_VOID: {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000272 current_block_->AddInstruction(new (arena_) HReturnVoid());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000273 current_block_->AddSuccessor(exit_block_);
274 current_block_ = nullptr;
275 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000276 }
277
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000278 case Instruction::IF_EQ: {
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100279 If_22t<HEqual>(instruction, dex_offset, false);
280 break;
281 }
282
283 case Instruction::IF_NE: {
284 If_22t<HEqual>(instruction, dex_offset, true);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000285 break;
286 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000287
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000288 case Instruction::GOTO:
289 case Instruction::GOTO_16:
290 case Instruction::GOTO_32: {
291 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
292 DCHECK(target != nullptr);
293 current_block_->AddInstruction(new (arena_) HGoto());
294 current_block_->AddSuccessor(target);
295 current_block_ = nullptr;
296 break;
297 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000298
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100299 case Instruction::RETURN:
300 case Instruction::RETURN_OBJECT: {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000301 HInstruction* value = LoadLocal(instruction.VRegA());
302 current_block_->AddInstruction(new (arena_) HReturn(value));
303 current_block_->AddSuccessor(exit_block_);
304 current_block_ = nullptr;
305 break;
306 }
307
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100308 case Instruction::INVOKE_STATIC:
309 case Instruction::INVOKE_DIRECT: {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000310 uint32_t method_idx = instruction.VRegB_35c();
311 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
312 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
313 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
314 const size_t number_of_arguments = instruction.VRegA_35c();
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100315
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000316 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
317 return false;
318 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100319
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100320 // Treat invoke-direct like static calls for now.
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100321 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
322 arena_, number_of_arguments, dex_offset, method_idx);
323
324 uint32_t args[5];
325 instruction.GetArgs(args);
326
327 for (size_t i = 0; i < number_of_arguments; i++) {
328 HInstruction* arg = LoadLocal(args[i]);
329 HInstruction* push = new (arena_) HPushArgument(arg, i);
330 current_block_->AddInstruction(push);
331 invoke->SetArgumentAt(i, push);
332 }
333
334 current_block_->AddInstruction(invoke);
335 break;
336 }
337
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100338 case Instruction::INVOKE_STATIC_RANGE:
339 case Instruction::INVOKE_DIRECT_RANGE: {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100340 uint32_t method_idx = instruction.VRegB_3rc();
341 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
342 uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
343 const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
344 const size_t number_of_arguments = instruction.VRegA_3rc();
345
346 if (Primitive::GetType(descriptor[0]) != Primitive::kPrimVoid) {
347 return false;
348 }
349
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100350 // Treat invoke-direct like static calls for now.
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100351 HInvokeStatic* invoke = new (arena_) HInvokeStatic(
352 arena_, number_of_arguments, dex_offset, method_idx);
353 int32_t register_index = instruction.VRegC();
354 for (size_t i = 0; i < number_of_arguments; i++) {
355 HInstruction* arg = LoadLocal(register_index + i);
356 HInstruction* push = new (arena_) HPushArgument(arg, i);
357 current_block_->AddInstruction(push);
358 invoke->SetArgumentAt(i, push);
359 }
360 current_block_->AddInstruction(invoke);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000361 break;
362 }
363
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000364 case Instruction::ADD_INT: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100365 Binop_32x<HAdd>(instruction);
366 break;
367 }
368
369 case Instruction::SUB_INT: {
370 Binop_32x<HSub>(instruction);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000371 break;
372 }
373
374 case Instruction::ADD_INT_2ADDR: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100375 Binop_12x<HAdd>(instruction);
376 break;
377 }
378
379 case Instruction::SUB_INT_2ADDR: {
380 Binop_12x<HSub>(instruction);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000381 break;
382 }
383
384 case Instruction::ADD_INT_LIT16: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100385 Binop_22s<HAdd>(instruction, false);
386 break;
387 }
388
389 case Instruction::RSUB_INT: {
390 Binop_22s<HSub>(instruction, true);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000391 break;
392 }
393
394 case Instruction::ADD_INT_LIT8: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100395 Binop_22b<HAdd>(instruction, false);
396 break;
397 }
398
399 case Instruction::RSUB_INT_LIT8: {
400 Binop_22b<HSub>(instruction, true);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000401 break;
402 }
403
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100404 case Instruction::NEW_INSTANCE: {
405 current_block_->AddInstruction(
406 new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
407 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
408 break;
409 }
410
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000411 case Instruction::NOP:
412 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000413
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000414 default:
415 return false;
416 }
417 return true;
418}
419
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000420HIntConstant* HGraphBuilder::GetConstant0() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000421 if (constant0_ != nullptr) {
422 return constant0_;
423 }
424 constant0_ = new(arena_) HIntConstant(0);
425 entry_block_->AddInstruction(constant0_);
426 return constant0_;
427}
428
429HIntConstant* HGraphBuilder::GetConstant1() {
430 if (constant1_ != nullptr) {
431 return constant1_;
432 }
433 constant1_ = new(arena_) HIntConstant(1);
434 entry_block_->AddInstruction(constant1_);
435 return constant1_;
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000436}
437
438HIntConstant* HGraphBuilder::GetConstant(int constant) {
439 switch (constant) {
440 case 0: return GetConstant0();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000441 case 1: return GetConstant1();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000442 default: {
443 HIntConstant* instruction = new (arena_) HIntConstant(constant);
444 entry_block_->AddInstruction(instruction);
445 return instruction;
446 }
447 }
448}
449
450HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
451 return locals_.Get(register_index);
452}
453
454void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
455 HLocal* local = GetLocalAt(register_index);
456 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
457}
458
459HInstruction* HGraphBuilder::LoadLocal(int register_index) const {
460 HLocal* local = GetLocalAt(register_index);
461 current_block_->AddInstruction(new (arena_) HLoadLocal(local));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000462 return current_block_->GetLastInstruction();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000463}
464
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000465} // namespace art