blob: f5941291e7e8838d06550dcd227aca72582ce135 [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 Geoffraye5038322014-07-04 09:41:32 +010018#include "builder.h"
19
20#include "class_linker.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000021#include "dex_file.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000022#include "dex_file-inl.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000023#include "dex_instruction.h"
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000024#include "dex_instruction-inl.h"
Nicolas Geoffraye5038322014-07-04 09:41:32 +010025#include "driver/compiler_driver-inl.h"
26#include "mirror/art_field.h"
27#include "mirror/art_field-inl.h"
28#include "mirror/class_loader.h"
29#include "mirror/dex_cache.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000030#include "nodes.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000031#include "primitive.h"
Nicolas Geoffraye5038322014-07-04 09:41:32 +010032#include "scoped_thread_state_change.h"
33#include "thread.h"
Nicolas Geoffray818f2102014-02-18 16:43:35 +000034
35namespace art {
36
Nicolas Geoffrayabed4d02014-07-14 15:24:11 +010037static bool IsTypeSupported(Primitive::Type type) {
38 return type != Primitive::kPrimFloat && type != Primitive::kPrimDouble;
39}
40
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010041void HGraphBuilder::InitializeLocals(uint16_t count) {
42 graph_->SetNumberOfVRegs(count);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000043 locals_.SetSize(count);
44 for (int i = 0; i < count; i++) {
45 HLocal* local = new (arena_) HLocal(i);
46 entry_block_->AddInstruction(local);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +000047 locals_.Put(i, local);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +000048 }
49}
50
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010051bool HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
52 // dex_compilation_unit_ is null only when unit testing.
53 if (dex_compilation_unit_ == nullptr) {
54 return true;
55 }
56
57 graph_->SetNumberOfInVRegs(number_of_parameters);
58 const char* shorty = dex_compilation_unit_->GetShorty();
59 int locals_index = locals_.Size() - number_of_parameters;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010060 int parameter_index = 0;
61
62 if (!dex_compilation_unit_->IsStatic()) {
63 // Add the implicit 'this' argument, not expressed in the signature.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010064 HParameterValue* parameter =
65 new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010066 entry_block_->AddInstruction(parameter);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010067 HLocal* local = GetLocalAt(locals_index++);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010068 entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010069 number_of_parameters--;
70 }
71
72 uint32_t pos = 1;
73 for (int i = 0; i < number_of_parameters; i++) {
74 switch (shorty[pos++]) {
75 case 'F':
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010076 case 'D': {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010077 return false;
78 }
79
80 default: {
81 // integer and reference parameters.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010082 HParameterValue* parameter =
83 new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos - 1]));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010084 entry_block_->AddInstruction(parameter);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010085 HLocal* local = GetLocalAt(locals_index++);
86 // Store the parameter value in the local that the dex code will use
87 // to reference that parameter.
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +010088 entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010089 if (parameter->GetType() == Primitive::kPrimLong) {
90 i++;
91 locals_index++;
92 parameter_index++;
93 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +010094 break;
95 }
96 }
97 }
98 return true;
99}
100
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000101static bool CanHandleCodeItem(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000102 if (code_item.tries_size_ > 0) {
103 return false;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000104 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000105 return true;
106}
107
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100108template<typename T>
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100109void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100110 HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
111 HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
Dave Allison20dfc792014-06-16 20:44:29 -0700112 T* comparison = new (arena_) T(first, second);
113 current_block_->AddInstruction(comparison);
114 HInstruction* ifinst = new (arena_) HIf(comparison);
115 current_block_->AddInstruction(ifinst);
116 HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
117 DCHECK(target != nullptr);
118 current_block_->AddSuccessor(target);
119 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
120 DCHECK(target != nullptr);
121 current_block_->AddSuccessor(target);
122 current_block_ = nullptr;
123}
124
125template<typename T>
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100126void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset) {
Dave Allison20dfc792014-06-16 20:44:29 -0700127 HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
128 T* comparison = new (arena_) T(value, GetIntConstant(0));
129 current_block_->AddInstruction(comparison);
130 HInstruction* ifinst = new (arena_) HIf(comparison);
131 current_block_->AddInstruction(ifinst);
132 HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100133 DCHECK(target != nullptr);
134 current_block_->AddSuccessor(target);
135 target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
136 DCHECK(target != nullptr);
137 current_block_->AddSuccessor(target);
138 current_block_ = nullptr;
139}
140
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000141HGraph* HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000142 if (!CanHandleCodeItem(code_item)) {
143 return nullptr;
144 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000145
146 const uint16_t* code_ptr = code_item.insns_;
147 const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
148
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000149 // Setup the graph with the entry block and exit block.
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000150 graph_ = new (arena_) HGraph(arena_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000151 entry_block_ = new (arena_) HBasicBlock(graph_);
152 graph_->AddBlock(entry_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000153 exit_block_ = new (arena_) HBasicBlock(graph_);
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000154 graph_->SetEntryBlock(entry_block_);
155 graph_->SetExitBlock(exit_block_);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000156
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000157 InitializeLocals(code_item.registers_size_);
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100158 graph_->UpdateMaximumNumberOfOutVRegs(code_item.outs_size_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000159
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000160 // To avoid splitting blocks, we compute ahead of time the instructions that
161 // start a new block, and create these blocks.
162 ComputeBranchTargets(code_ptr, code_end);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000163
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100164 if (!InitializeParameters(code_item.ins_size_)) {
165 return nullptr;
166 }
167
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000168 size_t dex_offset = 0;
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000169 while (code_ptr < code_end) {
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000170 // Update the current block if dex_offset starts a new block.
171 MaybeUpdateCurrentBlock(dex_offset);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000172 const Instruction& instruction = *Instruction::At(code_ptr);
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000173 if (!AnalyzeDexInstruction(instruction, dex_offset)) return nullptr;
174 dex_offset += instruction.SizeInCodeUnits();
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000175 code_ptr += instruction.SizeInCodeUnits();
176 }
177
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000178 // Add the exit block at the end to give it the highest id.
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000179 graph_->AddBlock(exit_block_);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000180 exit_block_->AddInstruction(new (arena_) HExit());
181 entry_block_->AddInstruction(new (arena_) HGoto());
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000182 return graph_;
183}
184
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000185void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) {
186 HBasicBlock* block = FindBlockStartingAt(index);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000187 if (block == nullptr) {
188 return;
189 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000190
191 if (current_block_ != nullptr) {
192 // Branching instructions clear current_block, so we know
193 // the last instruction of the current block is not a branching
194 // instruction. We add an unconditional goto to the found block.
195 current_block_->AddInstruction(new (arena_) HGoto());
196 current_block_->AddSuccessor(block);
197 }
198 graph_->AddBlock(block);
199 current_block_ = block;
200}
201
202void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end) {
203 // TODO: Support switch instructions.
204 branch_targets_.SetSize(code_end - code_ptr);
205
206 // Create the first block for the dex instructions, single successor of the entry block.
207 HBasicBlock* block = new (arena_) HBasicBlock(graph_);
208 branch_targets_.Put(0, block);
209 entry_block_->AddSuccessor(block);
210
211 // Iterate over all instructions and find branching instructions. Create blocks for
212 // the locations these instructions branch to.
213 size_t dex_offset = 0;
214 while (code_ptr < code_end) {
215 const Instruction& instruction = *Instruction::At(code_ptr);
216 if (instruction.IsBranch()) {
217 int32_t target = instruction.GetTargetOffset() + dex_offset;
218 // Create a block for the target instruction.
219 if (FindBlockStartingAt(target) == nullptr) {
220 block = new (arena_) HBasicBlock(graph_);
221 branch_targets_.Put(target, block);
222 }
223 dex_offset += instruction.SizeInCodeUnits();
224 code_ptr += instruction.SizeInCodeUnits();
225 if ((code_ptr < code_end) && (FindBlockStartingAt(dex_offset) == nullptr)) {
226 block = new (arena_) HBasicBlock(graph_);
227 branch_targets_.Put(dex_offset, block);
228 }
229 } else {
230 code_ptr += instruction.SizeInCodeUnits();
231 dex_offset += instruction.SizeInCodeUnits();
232 }
233 }
234}
235
236HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const {
237 DCHECK_GE(index, 0);
238 return branch_targets_.Get(index);
239}
240
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100241template<typename T>
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100242void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100243 HInstruction* first = LoadLocal(instruction.VRegB(), type);
244 HInstruction* second = LoadLocal(instruction.VRegC(), type);
245 current_block_->AddInstruction(new (arena_) T(type, first, second));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100246 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
247}
248
249template<typename T>
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100250void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) {
251 HInstruction* first = LoadLocal(instruction.VRegA(), type);
252 HInstruction* second = LoadLocal(instruction.VRegB(), type);
253 current_block_->AddInstruction(new (arena_) T(type, first, second));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100254 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
255}
256
257template<typename T>
258void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100259 HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
260 HInstruction* second = GetIntConstant(instruction.VRegC_22s());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100261 if (reverse) {
262 std::swap(first, second);
263 }
264 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
265 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
266}
267
268template<typename T>
269void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100270 HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
271 HInstruction* second = GetIntConstant(instruction.VRegC_22b());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100272 if (reverse) {
273 std::swap(first, second);
274 }
275 current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
276 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
277}
278
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100279void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
280 if (type == Primitive::kPrimVoid) {
281 current_block_->AddInstruction(new (arena_) HReturnVoid());
282 } else {
283 HInstruction* value = LoadLocal(instruction.VRegA(), type);
284 current_block_->AddInstruction(new (arena_) HReturn(value));
285 }
286 current_block_->AddSuccessor(exit_block_);
287 current_block_ = nullptr;
288}
289
290bool HGraphBuilder::BuildInvoke(const Instruction& instruction,
291 uint32_t dex_offset,
292 uint32_t method_idx,
293 uint32_t number_of_vreg_arguments,
294 bool is_range,
295 uint32_t* args,
296 uint32_t register_index) {
297 const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
298 const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_);
299 const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_);
300 Primitive::Type return_type = Primitive::GetType(descriptor[0]);
301 bool is_instance_call =
302 instruction.Opcode() != Instruction::INVOKE_STATIC
303 && instruction.Opcode() != Instruction::INVOKE_STATIC_RANGE;
304 const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
305
306 // Treat invoke-direct like static calls for now.
307 HInvoke* invoke = new (arena_) HInvokeStatic(
308 arena_, number_of_arguments, return_type, dex_offset, method_idx);
309
310 size_t start_index = 0;
311 if (is_instance_call) {
312 HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100313 invoke->SetArgumentAt(0, arg);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100314 start_index = 1;
315 }
316
317 uint32_t descriptor_index = 1;
318 uint32_t argument_index = start_index;
319 for (size_t i = start_index; i < number_of_vreg_arguments; i++, argument_index++) {
320 Primitive::Type type = Primitive::GetType(descriptor[descriptor_index++]);
Nicolas Geoffrayabed4d02014-07-14 15:24:11 +0100321 if (!IsTypeSupported(type)) {
322 return false;
323 }
324 if (!is_range && type == Primitive::kPrimLong && args[i] + 1 != args[i + 1]) {
325 LOG(WARNING) << "Non sequential register pair in " << dex_compilation_unit_->GetSymbol()
326 << " at " << dex_offset;
327 // We do not implement non sequential register pair.
328 return false;
329 }
330 HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
331 invoke->SetArgumentAt(argument_index, arg);
332 if (type == Primitive::kPrimLong) {
333 i++;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100334 }
335 }
336
Nicolas Geoffrayabed4d02014-07-14 15:24:11 +0100337 if (!IsTypeSupported(return_type)) {
Nicolas Geoffrayf635e632014-05-14 09:43:38 +0100338 return false;
339 }
340
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100341 DCHECK_EQ(argument_index, number_of_arguments);
342 current_block_->AddInstruction(invoke);
343 return true;
344}
345
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100346/**
347 * Helper class to add HTemporary instructions. This class is used when
348 * converting a DEX instruction to multiple HInstruction, and where those
349 * instructions do not die at the following instruction, but instead spans
350 * multiple instructions.
351 */
352class Temporaries : public ValueObject {
353 public:
354 Temporaries(HGraph* graph, size_t count) : graph_(graph), count_(count), index_(0) {
355 graph_->UpdateNumberOfTemporaries(count_);
356 }
357
358 void Add(HInstruction* instruction) {
359 // We currently only support vreg size temps.
360 DCHECK(instruction->GetType() != Primitive::kPrimLong
361 && instruction->GetType() != Primitive::kPrimDouble);
362 HInstruction* temp = new (graph_->GetArena()) HTemporary(index_++);
363 instruction->GetBlock()->AddInstruction(temp);
364 DCHECK(temp->GetPrevious() == instruction);
365 }
366
367 private:
368 HGraph* const graph_;
369
370 // The total number of temporaries that will be used.
371 const size_t count_;
372
373 // Current index in the temporary stack, updated by `Add`.
374 size_t index_;
375};
376
377bool HGraphBuilder::BuildFieldAccess(const Instruction& instruction,
378 uint32_t dex_offset,
379 bool is_put) {
380 uint32_t source_or_dest_reg = instruction.VRegA_22c();
381 uint32_t obj_reg = instruction.VRegB_22c();
382 uint16_t field_index = instruction.VRegC_22c();
383
384 ScopedObjectAccess soa(Thread::Current());
385 StackHandleScope<1> hs(soa.Self());
386 Handle<mirror::ArtField> resolved_field(hs.NewHandle(
387 compiler_driver_->ComputeInstanceFieldInfo(field_index, dex_compilation_unit_, is_put, soa)));
388
389 if (resolved_field.Get() == nullptr) {
390 return false;
391 }
392 if (resolved_field->IsVolatile()) {
393 return false;
394 }
395
Nicolas Geoffrayabed4d02014-07-14 15:24:11 +0100396 Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
397 if (!IsTypeSupported(field_type)) {
398 return false;
399 }
400
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100401 HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot);
402 current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_offset));
403 if (is_put) {
404 Temporaries temps(graph_, 1);
405 HInstruction* null_check = current_block_->GetLastInstruction();
406 // We need one temporary for the null check.
407 temps.Add(null_check);
Nicolas Geoffrayabed4d02014-07-14 15:24:11 +0100408 HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100409 current_block_->AddInstruction(new (arena_) HInstanceFieldSet(
410 null_check,
411 value,
412 resolved_field->GetOffset()));
413 } else {
414 current_block_->AddInstruction(new (arena_) HInstanceFieldGet(
415 current_block_->GetLastInstruction(),
Nicolas Geoffrayabed4d02014-07-14 15:24:11 +0100416 field_type,
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100417 resolved_field->GetOffset()));
418
419 UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
420 }
421 return true;
422}
423
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000424bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000425 if (current_block_ == nullptr) {
426 return true; // Dead code
427 }
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000428
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000429 switch (instruction.Opcode()) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000430 case Instruction::CONST_4: {
431 int32_t register_index = instruction.VRegA();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100432 HIntConstant* constant = GetIntConstant(instruction.VRegB_11n());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000433 UpdateLocal(register_index, constant);
434 break;
435 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000436
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100437 case Instruction::CONST_16: {
438 int32_t register_index = instruction.VRegA();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100439 HIntConstant* constant = GetIntConstant(instruction.VRegB_21s());
440 UpdateLocal(register_index, constant);
441 break;
442 }
443
Dave Allison20dfc792014-06-16 20:44:29 -0700444 case Instruction::CONST: {
445 int32_t register_index = instruction.VRegA();
446 HIntConstant* constant = GetIntConstant(instruction.VRegB_31i());
447 UpdateLocal(register_index, constant);
448 break;
449 }
450
451 case Instruction::CONST_HIGH16: {
452 int32_t register_index = instruction.VRegA();
453 HIntConstant* constant = GetIntConstant(instruction.VRegB_21h() << 16);
454 UpdateLocal(register_index, constant);
455 break;
456 }
457
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100458 case Instruction::CONST_WIDE_16: {
459 int32_t register_index = instruction.VRegA();
Dave Allison20dfc792014-06-16 20:44:29 -0700460 // Get 16 bits of constant value, sign extended to 64 bits.
461 int64_t value = instruction.VRegB_21s();
462 value <<= 48;
463 value >>= 48;
464 HLongConstant* constant = GetLongConstant(value);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100465 UpdateLocal(register_index, constant);
466 break;
467 }
468
469 case Instruction::CONST_WIDE_32: {
470 int32_t register_index = instruction.VRegA();
Dave Allison20dfc792014-06-16 20:44:29 -0700471 // Get 32 bits of constant value, sign extended to 64 bits.
472 int64_t value = instruction.VRegB_31i();
473 value <<= 32;
474 value >>= 32;
475 HLongConstant* constant = GetLongConstant(value);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100476 UpdateLocal(register_index, constant);
477 break;
478 }
479
480 case Instruction::CONST_WIDE: {
481 int32_t register_index = instruction.VRegA();
482 HLongConstant* constant = GetLongConstant(instruction.VRegB_51l());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100483 UpdateLocal(register_index, constant);
484 break;
485 }
486
Dave Allison20dfc792014-06-16 20:44:29 -0700487 case Instruction::CONST_WIDE_HIGH16: {
488 int32_t register_index = instruction.VRegA();
489 int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48;
490 HLongConstant* constant = GetLongConstant(value);
491 UpdateLocal(register_index, constant);
492 break;
493 }
494
495 // TODO: these instructions are also used to move floating point values, so what is
496 // the type (int or float)?
497 case Instruction::MOVE:
498 case Instruction::MOVE_FROM16:
499 case Instruction::MOVE_16: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100500 HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100501 UpdateLocal(instruction.VRegA(), value);
502 break;
503 }
504
Dave Allison20dfc792014-06-16 20:44:29 -0700505 // TODO: these instructions are also used to move floating point values, so what is
506 // the type (long or double)?
507 case Instruction::MOVE_WIDE:
508 case Instruction::MOVE_WIDE_FROM16:
509 case Instruction::MOVE_WIDE_16: {
510 HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong);
511 UpdateLocal(instruction.VRegA(), value);
512 break;
513 }
514
515 case Instruction::MOVE_OBJECT:
516 case Instruction::MOVE_OBJECT_16:
517 case Instruction::MOVE_OBJECT_FROM16: {
518 HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot);
519 UpdateLocal(instruction.VRegA(), value);
520 break;
521 }
522
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000523 case Instruction::RETURN_VOID: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100524 BuildReturn(instruction, Primitive::kPrimVoid);
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000525 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000526 }
527
Dave Allison20dfc792014-06-16 20:44:29 -0700528#define IF_XX(comparison, cond) \
529 case Instruction::IF_##cond: If_22t<comparison>(instruction, dex_offset); break; \
530 case Instruction::IF_##cond##Z: If_21t<comparison>(instruction, dex_offset); break
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100531
Dave Allison20dfc792014-06-16 20:44:29 -0700532 IF_XX(HEqual, EQ);
533 IF_XX(HNotEqual, NE);
534 IF_XX(HLessThan, LT);
535 IF_XX(HLessThanOrEqual, LE);
536 IF_XX(HGreaterThan, GT);
537 IF_XX(HGreaterThanOrEqual, GE);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000538
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000539 case Instruction::GOTO:
540 case Instruction::GOTO_16:
541 case Instruction::GOTO_32: {
542 HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
543 DCHECK(target != nullptr);
544 current_block_->AddInstruction(new (arena_) HGoto());
545 current_block_->AddSuccessor(target);
546 current_block_ = nullptr;
547 break;
548 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000549
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100550 case Instruction::RETURN: {
551 BuildReturn(instruction, Primitive::kPrimInt);
552 break;
553 }
554
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100555 case Instruction::RETURN_OBJECT: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100556 BuildReturn(instruction, Primitive::kPrimNot);
557 break;
558 }
559
560 case Instruction::RETURN_WIDE: {
561 BuildReturn(instruction, Primitive::kPrimLong);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000562 break;
563 }
564
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100565 case Instruction::INVOKE_STATIC:
566 case Instruction::INVOKE_DIRECT: {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000567 uint32_t method_idx = instruction.VRegB_35c();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100568 uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100569 uint32_t args[5];
Ian Rogers29a26482014-05-02 15:27:29 -0700570 instruction.GetVarArgs(args);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100571 if (!BuildInvoke(instruction, dex_offset, method_idx, number_of_vreg_arguments, false, args, -1)) {
572 return false;
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100573 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100574 break;
575 }
576
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100577 case Instruction::INVOKE_STATIC_RANGE:
578 case Instruction::INVOKE_DIRECT_RANGE: {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100579 uint32_t method_idx = instruction.VRegB_3rc();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100580 uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
581 uint32_t register_index = instruction.VRegC();
582 if (!BuildInvoke(instruction, dex_offset, method_idx,
583 number_of_vreg_arguments, true, nullptr, register_index)) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100584 return false;
585 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000586 break;
587 }
588
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000589 case Instruction::ADD_INT: {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100590 Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100591 break;
592 }
593
594 case Instruction::ADD_LONG: {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100595 Binop_23x<HAdd>(instruction, Primitive::kPrimLong);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100596 break;
597 }
598
599 case Instruction::SUB_INT: {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100600 Binop_23x<HSub>(instruction, Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100601 break;
602 }
603
604 case Instruction::SUB_LONG: {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100605 Binop_23x<HSub>(instruction, Primitive::kPrimLong);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000606 break;
607 }
608
609 case Instruction::ADD_INT_2ADDR: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100610 Binop_12x<HAdd>(instruction, Primitive::kPrimInt);
611 break;
612 }
613
614 case Instruction::ADD_LONG_2ADDR: {
615 Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100616 break;
617 }
618
619 case Instruction::SUB_INT_2ADDR: {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100620 Binop_12x<HSub>(instruction, Primitive::kPrimInt);
621 break;
622 }
623
624 case Instruction::SUB_LONG_2ADDR: {
625 Binop_12x<HSub>(instruction, Primitive::kPrimLong);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000626 break;
627 }
628
629 case Instruction::ADD_INT_LIT16: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100630 Binop_22s<HAdd>(instruction, false);
631 break;
632 }
633
634 case Instruction::RSUB_INT: {
635 Binop_22s<HSub>(instruction, true);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000636 break;
637 }
638
639 case Instruction::ADD_INT_LIT8: {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100640 Binop_22b<HAdd>(instruction, false);
641 break;
642 }
643
644 case Instruction::RSUB_INT_LIT8: {
645 Binop_22b<HSub>(instruction, true);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000646 break;
647 }
648
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100649 case Instruction::NEW_INSTANCE: {
650 current_block_->AddInstruction(
651 new (arena_) HNewInstance(dex_offset, instruction.VRegB_21c()));
652 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
653 break;
654 }
655
Nicolas Geoffrayddb311f2014-05-16 09:28:54 +0100656 case Instruction::MOVE_RESULT:
Dave Allison20dfc792014-06-16 20:44:29 -0700657 case Instruction::MOVE_RESULT_WIDE:
658 case Instruction::MOVE_RESULT_OBJECT:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100659 UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
660 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100661
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100662 case Instruction::CMP_LONG: {
663 Binop_23x<HCompare>(instruction, Primitive::kPrimLong);
664 break;
665 }
666
Nicolas Geoffraybe9a92a2014-02-25 14:22:56 +0000667 case Instruction::NOP:
668 break;
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000669
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100670 case Instruction::IGET:
671 case Instruction::IGET_WIDE:
672 case Instruction::IGET_OBJECT:
673 case Instruction::IGET_BOOLEAN:
674 case Instruction::IGET_BYTE:
675 case Instruction::IGET_CHAR:
676 case Instruction::IGET_SHORT: {
677 if (!BuildFieldAccess(instruction, dex_offset, false)) {
678 return false;
679 }
680 break;
681 }
682
683 case Instruction::IPUT:
684 case Instruction::IPUT_WIDE:
685 case Instruction::IPUT_OBJECT:
686 case Instruction::IPUT_BOOLEAN:
687 case Instruction::IPUT_BYTE:
688 case Instruction::IPUT_CHAR:
689 case Instruction::IPUT_SHORT: {
690 if (!BuildFieldAccess(instruction, dex_offset, true)) {
691 return false;
692 }
693 break;
694 }
695
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000696 default:
697 return false;
698 }
699 return true;
700}
701
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100702HIntConstant* HGraphBuilder::GetIntConstant0() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000703 if (constant0_ != nullptr) {
704 return constant0_;
705 }
706 constant0_ = new(arena_) HIntConstant(0);
707 entry_block_->AddInstruction(constant0_);
708 return constant0_;
709}
710
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100711HIntConstant* HGraphBuilder::GetIntConstant1() {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000712 if (constant1_ != nullptr) {
713 return constant1_;
714 }
715 constant1_ = new(arena_) HIntConstant(1);
716 entry_block_->AddInstruction(constant1_);
717 return constant1_;
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000718}
719
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100720HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000721 switch (constant) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100722 case 0: return GetIntConstant0();
723 case 1: return GetIntConstant1();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000724 default: {
725 HIntConstant* instruction = new (arena_) HIntConstant(constant);
726 entry_block_->AddInstruction(instruction);
727 return instruction;
728 }
729 }
730}
731
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100732HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
733 HLongConstant* instruction = new (arena_) HLongConstant(constant);
734 entry_block_->AddInstruction(instruction);
735 return instruction;
736}
737
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000738HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
739 return locals_.Get(register_index);
740}
741
742void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
743 HLocal* local = GetLocalAt(register_index);
744 current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
745}
746
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100747HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const {
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000748 HLocal* local = GetLocalAt(register_index);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100749 current_block_->AddInstruction(new (arena_) HLoadLocal(local, type));
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000750 return current_block_->GetLastInstruction();
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000751}
752
Nicolas Geoffray818f2102014-02-18 16:43:35 +0000753} // namespace art