local_value_numbering.cc revision 9820b7c1dc70e75ad405b9e6e63578fa9fe94e94
1/*
2 * Copyright (C) 2012 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 "local_value_numbering.h"
18
19#include "mir_field_info.h"
20#include "mir_graph.h"
21
22namespace art {
23
24uint16_t LocalValueNumbering::GetFieldId(const DexFile* dex_file, uint16_t field_idx) {
25  FieldReference key = { dex_file, field_idx };
26  auto it = field_index_map_.find(key);
27  if (it != field_index_map_.end()) {
28    return it->second;
29  }
30  uint16_t id = field_index_map_.size();
31  field_index_map_.Put(key, id);
32  return id;
33}
34
35void LocalValueNumbering::AdvanceGlobalMemory() {
36  // See AdvanceMemoryVersion() for explanation.
37  global_memory_version_ = next_memory_version_;
38  ++next_memory_version_;
39}
40
41uint16_t LocalValueNumbering::GetMemoryVersion(uint16_t base, uint16_t field, uint16_t type) {
42  // See AdvanceMemoryVersion() for explanation.
43  MemoryVersionKey key = { base, field, type };
44  MemoryVersionMap::iterator it = memory_version_map_.find(key);
45  uint16_t memory_version = (it != memory_version_map_.end()) ? it->second : 0u;
46  if (base != NO_VALUE && non_aliasing_refs_.find(base) == non_aliasing_refs_.end()) {
47    // Check modifications by potentially aliased access.
48    MemoryVersionKey aliased_access_key = { NO_VALUE, field, type };
49    auto aa_it = memory_version_map_.find(aliased_access_key);
50    if (aa_it != memory_version_map_.end() && aa_it->second > memory_version) {
51      memory_version = aa_it->second;
52    }
53    memory_version = std::max(memory_version, global_memory_version_);
54  } else if (base != NO_VALUE) {
55    // Ignore global_memory_version_ for access via unique references.
56  } else {
57    memory_version = std::max(memory_version, global_memory_version_);
58  }
59  return memory_version;
60};
61
62uint16_t LocalValueNumbering::AdvanceMemoryVersion(uint16_t base, uint16_t field, uint16_t type) {
63  // When we read the same value from memory, we want to assign the same value name to it.
64  // However, we need to be careful not to assign the same value name if the memory location
65  // may have been written to between the reads. To avoid that we do "memory versioning".
66  //
67  // For each write to a memory location (instance field, static field, array element) we assign
68  // a new memory version number to the location identified by the value name of the base register,
69  // the field id and type, or "{ base, field, type }". For static fields the "base" is NO_VALUE
70  // since they are not accessed via a reference. For arrays the "field" is NO_VALUE since they
71  // don't have a field id.
72  //
73  // To account for the possibility of aliased access to the same memory location via different
74  // "base", we also store the memory version number with the key "{ NO_VALUE, field, type }"
75  // if "base" is an aliasing reference and check it in GetMemoryVersion() on reads via
76  // aliasing references. A global memory version is set for method calls as a method can
77  // potentially write to any memory location accessed via an aliasing reference.
78
79  uint16_t result = next_memory_version_;
80  ++next_memory_version_;
81  MemoryVersionKey key = { base, field, type };
82  memory_version_map_.Overwrite(key, result);
83  if (base != NO_VALUE && non_aliasing_refs_.find(base) == non_aliasing_refs_.end()) {
84    // Advance memory version for aliased access.
85    MemoryVersionKey aliased_access_key = { NO_VALUE, field, type };
86    memory_version_map_.Overwrite(aliased_access_key, result);
87  }
88  return result;
89};
90
91uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
92  uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
93  SetOperandValue(mir->ssa_rep->defs[0], res);
94  DCHECK(null_checked_.find(res) == null_checked_.end());
95  null_checked_.insert(res);
96  non_aliasing_refs_.insert(res);
97  return res;
98}
99
100void LocalValueNumbering::MakeArgsAliasing(MIR* mir) {
101  for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
102    uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
103    non_aliasing_refs_.erase(reg);
104  }
105}
106
107void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
108  if (null_checked_.find(reg) != null_checked_.end()) {
109    if (cu_->verbose) {
110      LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
111    }
112    mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
113  } else {
114    null_checked_.insert(reg);
115  }
116}
117
118void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
119  if (ValueExists(ARRAY_REF, array, index, NO_VALUE)) {
120    if (cu_->verbose) {
121      LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
122    }
123    mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
124  }
125  // Use side effect to note range check completed.
126  (void)LookupValue(ARRAY_REF, array, index, NO_VALUE);
127}
128
129void LocalValueNumbering::HandlePutObject(MIR* mir) {
130  // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
131  uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
132  non_aliasing_refs_.erase(base);
133}
134
135uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
136  uint16_t res = NO_VALUE;
137  uint16_t opcode = mir->dalvikInsn.opcode;
138  switch (opcode) {
139    case Instruction::NOP:
140    case Instruction::RETURN_VOID:
141    case Instruction::RETURN:
142    case Instruction::RETURN_OBJECT:
143    case Instruction::RETURN_WIDE:
144    case Instruction::MONITOR_ENTER:
145    case Instruction::MONITOR_EXIT:
146    case Instruction::GOTO:
147    case Instruction::GOTO_16:
148    case Instruction::GOTO_32:
149    case Instruction::CHECK_CAST:
150    case Instruction::THROW:
151    case Instruction::FILL_ARRAY_DATA:
152    case Instruction::PACKED_SWITCH:
153    case Instruction::SPARSE_SWITCH:
154    case Instruction::IF_EQ:
155    case Instruction::IF_NE:
156    case Instruction::IF_LT:
157    case Instruction::IF_GE:
158    case Instruction::IF_GT:
159    case Instruction::IF_LE:
160    case Instruction::IF_EQZ:
161    case Instruction::IF_NEZ:
162    case Instruction::IF_LTZ:
163    case Instruction::IF_GEZ:
164    case Instruction::IF_GTZ:
165    case Instruction::IF_LEZ:
166    case kMirOpFusedCmplFloat:
167    case kMirOpFusedCmpgFloat:
168    case kMirOpFusedCmplDouble:
169    case kMirOpFusedCmpgDouble:
170    case kMirOpFusedCmpLong:
171      // Nothing defined - take no action.
172      break;
173
174    case Instruction::FILLED_NEW_ARRAY:
175    case Instruction::FILLED_NEW_ARRAY_RANGE:
176      // Nothing defined but the result will be unique and non-null.
177      if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
178        MarkNonAliasingNonNull(mir->next);
179        // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
180      }
181      MakeArgsAliasing(mir);
182      break;
183
184    case Instruction::INVOKE_DIRECT:
185    case Instruction::INVOKE_DIRECT_RANGE:
186    case Instruction::INVOKE_VIRTUAL:
187    case Instruction::INVOKE_VIRTUAL_RANGE:
188    case Instruction::INVOKE_SUPER:
189    case Instruction::INVOKE_SUPER_RANGE:
190    case Instruction::INVOKE_INTERFACE:
191    case Instruction::INVOKE_INTERFACE_RANGE: {
192        // Nothing defined but handle the null check.
193        uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
194        HandleNullCheck(mir, reg);
195      }
196      // Intentional fall-through.
197    case Instruction::INVOKE_STATIC:
198    case Instruction::INVOKE_STATIC_RANGE:
199      if ((mir->optimization_flags & MIR_INLINED) == 0) {
200        AdvanceGlobalMemory();
201        MakeArgsAliasing(mir);
202      }
203      break;
204
205    case Instruction::MOVE_RESULT:
206    case Instruction::MOVE_RESULT_OBJECT:
207    case Instruction::INSTANCE_OF:
208      // 1 result, treat as unique each time, use result s_reg - will be unique.
209      res = GetOperandValue(mir->ssa_rep->defs[0]);
210      SetOperandValue(mir->ssa_rep->defs[0], res);
211      break;
212    case Instruction::MOVE_EXCEPTION:
213    case Instruction::NEW_INSTANCE:
214    case Instruction::CONST_STRING:
215    case Instruction::CONST_STRING_JUMBO:
216    case Instruction::CONST_CLASS:
217    case Instruction::NEW_ARRAY:
218      if ((mir->optimization_flags & MIR_INLINED) == 0) {
219        // 1 result, treat as unique each time, use result s_reg - will be unique.
220        res = MarkNonAliasingNonNull(mir);
221      }
222      break;
223    case Instruction::MOVE_RESULT_WIDE:
224      if ((mir->optimization_flags & MIR_INLINED) == 0) {
225        // 1 wide result, treat as unique each time, use result s_reg - will be unique.
226        res = GetOperandValueWide(mir->ssa_rep->defs[0]);
227        SetOperandValueWide(mir->ssa_rep->defs[0], res);
228      }
229      break;
230
231    case kMirOpPhi:
232      /*
233       * Because we'll only see phi nodes at the beginning of an extended basic block,
234       * we can ignore them.  Revisit if we shift to global value numbering.
235       */
236      break;
237
238    case Instruction::MOVE:
239    case Instruction::MOVE_OBJECT:
240    case Instruction::MOVE_16:
241    case Instruction::MOVE_OBJECT_16:
242    case Instruction::MOVE_FROM16:
243    case Instruction::MOVE_OBJECT_FROM16:
244    case kMirOpCopy:
245      // Just copy value number of source to value number of result.
246      res = GetOperandValue(mir->ssa_rep->uses[0]);
247      SetOperandValue(mir->ssa_rep->defs[0], res);
248      break;
249
250    case Instruction::MOVE_WIDE:
251    case Instruction::MOVE_WIDE_16:
252    case Instruction::MOVE_WIDE_FROM16:
253      // Just copy value number of source to value number of result.
254      res = GetOperandValueWide(mir->ssa_rep->uses[0]);
255      SetOperandValueWide(mir->ssa_rep->defs[0], res);
256      break;
257
258    case Instruction::CONST:
259    case Instruction::CONST_4:
260    case Instruction::CONST_16:
261      res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
262                        High16Bits(mir->dalvikInsn.vB >> 16), 0);
263      SetOperandValue(mir->ssa_rep->defs[0], res);
264      break;
265
266    case Instruction::CONST_HIGH16:
267      res = LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
268      SetOperandValue(mir->ssa_rep->defs[0], res);
269      break;
270
271    case Instruction::CONST_WIDE_16:
272    case Instruction::CONST_WIDE_32: {
273        uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
274                                       High16Bits(mir->dalvikInsn.vB >> 16), 1);
275        uint16_t high_res;
276        if (mir->dalvikInsn.vB & 0x80000000) {
277          high_res = LookupValue(Instruction::CONST, 0xffff, 0xffff, 2);
278        } else {
279          high_res = LookupValue(Instruction::CONST, 0, 0, 2);
280        }
281        res = LookupValue(Instruction::CONST, low_res, high_res, 3);
282        SetOperandValueWide(mir->ssa_rep->defs[0], res);
283      }
284      break;
285
286    case Instruction::CONST_WIDE: {
287        uint32_t low_word = Low32Bits(mir->dalvikInsn.vB_wide);
288        uint32_t high_word = High32Bits(mir->dalvikInsn.vB_wide);
289        uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(low_word),
290                                       High16Bits(low_word), 1);
291        uint16_t high_res = LookupValue(Instruction::CONST, Low16Bits(high_word),
292                                       High16Bits(high_word), 2);
293        res = LookupValue(Instruction::CONST, low_res, high_res, 3);
294        SetOperandValueWide(mir->ssa_rep->defs[0], res);
295      }
296      break;
297
298    case Instruction::CONST_WIDE_HIGH16: {
299        uint16_t low_res = LookupValue(Instruction::CONST, 0, 0, 1);
300        uint16_t high_res = LookupValue(Instruction::CONST, 0, Low16Bits(mir->dalvikInsn.vB), 2);
301        res = LookupValue(Instruction::CONST, low_res, high_res, 3);
302        SetOperandValueWide(mir->ssa_rep->defs[0], res);
303      }
304      break;
305
306    case Instruction::ARRAY_LENGTH:
307    case Instruction::NEG_INT:
308    case Instruction::NOT_INT:
309    case Instruction::NEG_FLOAT:
310    case Instruction::INT_TO_BYTE:
311    case Instruction::INT_TO_SHORT:
312    case Instruction::INT_TO_CHAR:
313    case Instruction::INT_TO_FLOAT:
314    case Instruction::FLOAT_TO_INT: {
315        // res = op + 1 operand
316        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
317        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
318        SetOperandValue(mir->ssa_rep->defs[0], res);
319      }
320      break;
321
322    case Instruction::LONG_TO_FLOAT:
323    case Instruction::LONG_TO_INT:
324    case Instruction::DOUBLE_TO_FLOAT:
325    case Instruction::DOUBLE_TO_INT: {
326        // res = op + 1 wide operand
327        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
328        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
329        SetOperandValue(mir->ssa_rep->defs[0], res);
330      }
331      break;
332
333
334    case Instruction::DOUBLE_TO_LONG:
335    case Instruction::LONG_TO_DOUBLE:
336    case Instruction::NEG_LONG:
337    case Instruction::NOT_LONG:
338    case Instruction::NEG_DOUBLE: {
339        // wide res = op + 1 wide operand
340        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
341        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
342        SetOperandValueWide(mir->ssa_rep->defs[0], res);
343      }
344      break;
345
346    case Instruction::FLOAT_TO_DOUBLE:
347    case Instruction::FLOAT_TO_LONG:
348    case Instruction::INT_TO_DOUBLE:
349    case Instruction::INT_TO_LONG: {
350        // wide res = op + 1 operand
351        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
352        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
353        SetOperandValueWide(mir->ssa_rep->defs[0], res);
354      }
355      break;
356
357    case Instruction::CMPL_DOUBLE:
358    case Instruction::CMPG_DOUBLE:
359    case Instruction::CMP_LONG: {
360        // res = op + 2 wide operands
361        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
362        uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
363        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
364        SetOperandValue(mir->ssa_rep->defs[0], res);
365      }
366      break;
367
368    case Instruction::CMPG_FLOAT:
369    case Instruction::CMPL_FLOAT:
370    case Instruction::ADD_INT:
371    case Instruction::ADD_INT_2ADDR:
372    case Instruction::MUL_INT:
373    case Instruction::MUL_INT_2ADDR:
374    case Instruction::AND_INT:
375    case Instruction::AND_INT_2ADDR:
376    case Instruction::OR_INT:
377    case Instruction::OR_INT_2ADDR:
378    case Instruction::XOR_INT:
379    case Instruction::XOR_INT_2ADDR:
380    case Instruction::SUB_INT:
381    case Instruction::SUB_INT_2ADDR:
382    case Instruction::DIV_INT:
383    case Instruction::DIV_INT_2ADDR:
384    case Instruction::REM_INT:
385    case Instruction::REM_INT_2ADDR:
386    case Instruction::SHL_INT:
387    case Instruction::SHL_INT_2ADDR:
388    case Instruction::SHR_INT:
389    case Instruction::SHR_INT_2ADDR:
390    case Instruction::USHR_INT:
391    case Instruction::USHR_INT_2ADDR: {
392        // res = op + 2 operands
393        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
394        uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
395        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
396        SetOperandValue(mir->ssa_rep->defs[0], res);
397      }
398      break;
399
400    case Instruction::ADD_LONG:
401    case Instruction::SUB_LONG:
402    case Instruction::MUL_LONG:
403    case Instruction::DIV_LONG:
404    case Instruction::REM_LONG:
405    case Instruction::AND_LONG:
406    case Instruction::OR_LONG:
407    case Instruction::XOR_LONG:
408    case Instruction::ADD_LONG_2ADDR:
409    case Instruction::SUB_LONG_2ADDR:
410    case Instruction::MUL_LONG_2ADDR:
411    case Instruction::DIV_LONG_2ADDR:
412    case Instruction::REM_LONG_2ADDR:
413    case Instruction::AND_LONG_2ADDR:
414    case Instruction::OR_LONG_2ADDR:
415    case Instruction::XOR_LONG_2ADDR:
416    case Instruction::ADD_DOUBLE:
417    case Instruction::SUB_DOUBLE:
418    case Instruction::MUL_DOUBLE:
419    case Instruction::DIV_DOUBLE:
420    case Instruction::REM_DOUBLE:
421    case Instruction::ADD_DOUBLE_2ADDR:
422    case Instruction::SUB_DOUBLE_2ADDR:
423    case Instruction::MUL_DOUBLE_2ADDR:
424    case Instruction::DIV_DOUBLE_2ADDR:
425    case Instruction::REM_DOUBLE_2ADDR: {
426        // wide res = op + 2 wide operands
427        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
428        uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
429        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
430        SetOperandValueWide(mir->ssa_rep->defs[0], res);
431      }
432      break;
433
434    case Instruction::SHL_LONG:
435    case Instruction::SHR_LONG:
436    case Instruction::USHR_LONG:
437    case Instruction::SHL_LONG_2ADDR:
438    case Instruction::SHR_LONG_2ADDR:
439    case Instruction::USHR_LONG_2ADDR: {
440        // wide res = op + 1 wide operand + 1 operand
441        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
442        uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
443        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
444        SetOperandValueWide(mir->ssa_rep->defs[0], res);
445      }
446      break;
447
448    case Instruction::ADD_FLOAT:
449    case Instruction::SUB_FLOAT:
450    case Instruction::MUL_FLOAT:
451    case Instruction::DIV_FLOAT:
452    case Instruction::REM_FLOAT:
453    case Instruction::ADD_FLOAT_2ADDR:
454    case Instruction::SUB_FLOAT_2ADDR:
455    case Instruction::MUL_FLOAT_2ADDR:
456    case Instruction::DIV_FLOAT_2ADDR:
457    case Instruction::REM_FLOAT_2ADDR: {
458        // res = op + 2 operands
459        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
460        uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
461        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
462        SetOperandValue(mir->ssa_rep->defs[0], res);
463      }
464      break;
465
466    case Instruction::RSUB_INT:
467    case Instruction::ADD_INT_LIT16:
468    case Instruction::MUL_INT_LIT16:
469    case Instruction::DIV_INT_LIT16:
470    case Instruction::REM_INT_LIT16:
471    case Instruction::AND_INT_LIT16:
472    case Instruction::OR_INT_LIT16:
473    case Instruction::XOR_INT_LIT16:
474    case Instruction::ADD_INT_LIT8:
475    case Instruction::RSUB_INT_LIT8:
476    case Instruction::MUL_INT_LIT8:
477    case Instruction::DIV_INT_LIT8:
478    case Instruction::REM_INT_LIT8:
479    case Instruction::AND_INT_LIT8:
480    case Instruction::OR_INT_LIT8:
481    case Instruction::XOR_INT_LIT8:
482    case Instruction::SHL_INT_LIT8:
483    case Instruction::SHR_INT_LIT8:
484    case Instruction::USHR_INT_LIT8: {
485        // Same as res = op + 2 operands, except use vB as operand 2
486        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
487        uint16_t operand2 = LookupValue(Instruction::CONST, mir->dalvikInsn.vB, 0, 0);
488        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
489        SetOperandValue(mir->ssa_rep->defs[0], res);
490      }
491      break;
492
493    case Instruction::AGET_OBJECT:
494    case Instruction::AGET:
495    case Instruction::AGET_WIDE:
496    case Instruction::AGET_BOOLEAN:
497    case Instruction::AGET_BYTE:
498    case Instruction::AGET_CHAR:
499    case Instruction::AGET_SHORT: {
500        uint16_t type = opcode - Instruction::AGET;
501        uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
502        HandleNullCheck(mir, array);
503        uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
504        HandleRangeCheck(mir, array, index);
505        // Establish value number for loaded register. Note use of memory version.
506        uint16_t memory_version = GetMemoryVersion(array, NO_VALUE, type);
507        uint16_t res = LookupValue(ARRAY_REF, array, index, memory_version);
508        if (opcode == Instruction::AGET_WIDE) {
509          SetOperandValueWide(mir->ssa_rep->defs[0], res);
510        } else {
511          SetOperandValue(mir->ssa_rep->defs[0], res);
512        }
513      }
514      break;
515
516    case Instruction::APUT_OBJECT:
517      HandlePutObject(mir);
518      // Intentional fall-through.
519    case Instruction::APUT:
520    case Instruction::APUT_WIDE:
521    case Instruction::APUT_BYTE:
522    case Instruction::APUT_BOOLEAN:
523    case Instruction::APUT_SHORT:
524    case Instruction::APUT_CHAR: {
525        uint16_t type = opcode - Instruction::APUT;
526        int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
527        int index_idx = array_idx + 1;
528        uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
529        HandleNullCheck(mir, array);
530        uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
531        HandleRangeCheck(mir, array, index);
532        // Rev the memory version
533        AdvanceMemoryVersion(array, NO_VALUE, type);
534      }
535      break;
536
537    case Instruction::IGET_OBJECT:
538    case Instruction::IGET:
539    case Instruction::IGET_WIDE:
540    case Instruction::IGET_BOOLEAN:
541    case Instruction::IGET_BYTE:
542    case Instruction::IGET_CHAR:
543    case Instruction::IGET_SHORT: {
544        uint16_t type = opcode - Instruction::IGET;
545        uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
546        HandleNullCheck(mir, base);
547        const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir);
548        uint16_t memory_version;
549        uint16_t field_id;
550        if (!field_info.IsResolved() || field_info.IsVolatile()) {
551          // Volatile fields always get a new memory version; field id is irrelevant.
552          // Unresolved fields may be volatile, so handle them as such to be safe.
553          field_id = 0u;
554          memory_version = next_memory_version_;
555          ++next_memory_version_;
556        } else {
557          DCHECK(field_info.IsResolved());
558          field_id = GetFieldId(field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex());
559          memory_version = std::max(unresolved_ifield_version_[type],
560                                    GetMemoryVersion(base, field_id, type));
561        }
562        if (opcode == Instruction::IGET_WIDE) {
563          res = LookupValue(Instruction::IGET_WIDE, base, field_id, memory_version);
564          SetOperandValueWide(mir->ssa_rep->defs[0], res);
565        } else {
566          res = LookupValue(Instruction::IGET, base, field_id, memory_version);
567          SetOperandValue(mir->ssa_rep->defs[0], res);
568        }
569      }
570      break;
571
572    case Instruction::IPUT_OBJECT:
573      HandlePutObject(mir);
574      // Intentional fall-through.
575    case Instruction::IPUT:
576    case Instruction::IPUT_WIDE:
577    case Instruction::IPUT_BOOLEAN:
578    case Instruction::IPUT_BYTE:
579    case Instruction::IPUT_CHAR:
580    case Instruction::IPUT_SHORT: {
581        uint16_t type = opcode - Instruction::IPUT;
582        int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
583        uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
584        HandleNullCheck(mir, base);
585        const MirFieldInfo& field_info = cu_->mir_graph->GetIFieldLoweringInfo(mir);
586        if (!field_info.IsResolved()) {
587          // Unresolved fields always alias with everything of the same type.
588          unresolved_ifield_version_[type] = next_memory_version_;
589          ++next_memory_version_;
590        } else if (field_info.IsVolatile()) {
591          // Nothing to do, resolved volatile fields always get a new memory version anyway and
592          // can't alias with resolved non-volatile fields.
593        } else {
594          AdvanceMemoryVersion(base, GetFieldId(field_info.DeclaringDexFile(),
595                                                field_info.DeclaringFieldIndex()), type);
596        }
597      }
598      break;
599
600    case Instruction::SGET_OBJECT:
601    case Instruction::SGET:
602    case Instruction::SGET_WIDE:
603    case Instruction::SGET_BOOLEAN:
604    case Instruction::SGET_BYTE:
605    case Instruction::SGET_CHAR:
606    case Instruction::SGET_SHORT: {
607        uint16_t type = opcode - Instruction::SGET;
608        const MirFieldInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir);
609        uint16_t memory_version;
610        uint16_t field_id;
611        if (!field_info.IsResolved() || field_info.IsVolatile()) {
612          // Volatile fields always get a new memory version; field id is irrelevant.
613          // Unresolved fields may be volatile, so handle them as such to be safe.
614          field_id = 0u;
615          memory_version = next_memory_version_;
616          ++next_memory_version_;
617        } else {
618          DCHECK(field_info.IsResolved());
619          field_id = GetFieldId(field_info.DeclaringDexFile(), field_info.DeclaringFieldIndex());
620          memory_version = std::max(unresolved_sfield_version_[type],
621                                    GetMemoryVersion(NO_VALUE, field_id, type));
622        }
623        if (opcode == Instruction::SGET_WIDE) {
624          res = LookupValue(Instruction::SGET_WIDE, NO_VALUE, field_id, memory_version);
625          SetOperandValueWide(mir->ssa_rep->defs[0], res);
626        } else {
627          res = LookupValue(Instruction::SGET, NO_VALUE, field_id, memory_version);
628          SetOperandValue(mir->ssa_rep->defs[0], res);
629        }
630      }
631      break;
632
633    case Instruction::SPUT_OBJECT:
634      HandlePutObject(mir);
635      // Intentional fall-through.
636    case Instruction::SPUT:
637    case Instruction::SPUT_WIDE:
638    case Instruction::SPUT_BOOLEAN:
639    case Instruction::SPUT_BYTE:
640    case Instruction::SPUT_CHAR:
641    case Instruction::SPUT_SHORT: {
642        uint16_t type = opcode - Instruction::SPUT;
643        const MirFieldInfo& field_info = cu_->mir_graph->GetSFieldLoweringInfo(mir);
644        if (!field_info.IsResolved()) {
645          // Unresolved fields always alias with everything of the same type.
646          unresolved_sfield_version_[type] = next_memory_version_;
647          ++next_memory_version_;
648        } else if (field_info.IsVolatile()) {
649          // Nothing to do, resolved volatile fields always get a new memory version anyway and
650          // can't alias with resolved non-volatile fields.
651        } else {
652          AdvanceMemoryVersion(NO_VALUE, GetFieldId(field_info.DeclaringDexFile(),
653                                                    field_info.DeclaringFieldIndex()), type);
654        }
655      }
656      break;
657  }
658  return res;
659}
660
661}    // namespace art
662