local_value_numbering.cc revision f59f18b2bd5432bb083205680c69fe64aaf60f39
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_annotations.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      AdvanceGlobalMemory();
200      MakeArgsAliasing(mir);
201      break;
202
203    case Instruction::MOVE_RESULT:
204    case Instruction::MOVE_RESULT_OBJECT:
205    case Instruction::INSTANCE_OF:
206      // 1 result, treat as unique each time, use result s_reg - will be unique.
207      res = GetOperandValue(mir->ssa_rep->defs[0]);
208      SetOperandValue(mir->ssa_rep->defs[0], res);
209      break;
210    case Instruction::MOVE_EXCEPTION:
211    case Instruction::NEW_INSTANCE:
212    case Instruction::CONST_STRING:
213    case Instruction::CONST_STRING_JUMBO:
214    case Instruction::CONST_CLASS:
215    case Instruction::NEW_ARRAY:
216      // 1 result, treat as unique each time, use result s_reg - will be unique.
217      res = MarkNonAliasingNonNull(mir);
218      break;
219    case Instruction::MOVE_RESULT_WIDE:
220      // 1 wide result, treat as unique each time, use result s_reg - will be unique.
221      res = GetOperandValueWide(mir->ssa_rep->defs[0]);
222      SetOperandValueWide(mir->ssa_rep->defs[0], res);
223      break;
224
225    case kMirOpPhi:
226      /*
227       * Because we'll only see phi nodes at the beginning of an extended basic block,
228       * we can ignore them.  Revisit if we shift to global value numbering.
229       */
230      break;
231
232    case Instruction::MOVE:
233    case Instruction::MOVE_OBJECT:
234    case Instruction::MOVE_16:
235    case Instruction::MOVE_OBJECT_16:
236    case Instruction::MOVE_FROM16:
237    case Instruction::MOVE_OBJECT_FROM16:
238    case kMirOpCopy:
239      // Just copy value number of source to value number of result.
240      res = GetOperandValue(mir->ssa_rep->uses[0]);
241      SetOperandValue(mir->ssa_rep->defs[0], res);
242      break;
243
244    case Instruction::MOVE_WIDE:
245    case Instruction::MOVE_WIDE_16:
246    case Instruction::MOVE_WIDE_FROM16:
247      // Just copy value number of source to value number of result.
248      res = GetOperandValueWide(mir->ssa_rep->uses[0]);
249      SetOperandValueWide(mir->ssa_rep->defs[0], res);
250      break;
251
252    case Instruction::CONST:
253    case Instruction::CONST_4:
254    case Instruction::CONST_16:
255      res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
256                        High16Bits(mir->dalvikInsn.vB >> 16), 0);
257      SetOperandValue(mir->ssa_rep->defs[0], res);
258      break;
259
260    case Instruction::CONST_HIGH16:
261      res = LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
262      SetOperandValue(mir->ssa_rep->defs[0], res);
263      break;
264
265    case Instruction::CONST_WIDE_16:
266    case Instruction::CONST_WIDE_32: {
267        uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
268                                       High16Bits(mir->dalvikInsn.vB >> 16), 1);
269        uint16_t high_res;
270        if (mir->dalvikInsn.vB & 0x80000000) {
271          high_res = LookupValue(Instruction::CONST, 0xffff, 0xffff, 2);
272        } else {
273          high_res = LookupValue(Instruction::CONST, 0, 0, 2);
274        }
275        res = LookupValue(Instruction::CONST, low_res, high_res, 3);
276        SetOperandValueWide(mir->ssa_rep->defs[0], res);
277      }
278      break;
279
280    case Instruction::CONST_WIDE: {
281        uint32_t low_word = Low32Bits(mir->dalvikInsn.vB_wide);
282        uint32_t high_word = High32Bits(mir->dalvikInsn.vB_wide);
283        uint16_t low_res = LookupValue(Instruction::CONST, Low16Bits(low_word),
284                                       High16Bits(low_word), 1);
285        uint16_t high_res = LookupValue(Instruction::CONST, Low16Bits(high_word),
286                                       High16Bits(high_word), 2);
287        res = LookupValue(Instruction::CONST, low_res, high_res, 3);
288        SetOperandValueWide(mir->ssa_rep->defs[0], res);
289      }
290      break;
291
292    case Instruction::CONST_WIDE_HIGH16: {
293        uint16_t low_res = LookupValue(Instruction::CONST, 0, 0, 1);
294        uint16_t high_res = LookupValue(Instruction::CONST, 0, Low16Bits(mir->dalvikInsn.vB), 2);
295        res = LookupValue(Instruction::CONST, low_res, high_res, 3);
296        SetOperandValueWide(mir->ssa_rep->defs[0], res);
297      }
298      break;
299
300    case Instruction::ARRAY_LENGTH:
301    case Instruction::NEG_INT:
302    case Instruction::NOT_INT:
303    case Instruction::NEG_FLOAT:
304    case Instruction::INT_TO_BYTE:
305    case Instruction::INT_TO_SHORT:
306    case Instruction::INT_TO_CHAR:
307    case Instruction::INT_TO_FLOAT:
308    case Instruction::FLOAT_TO_INT: {
309        // res = op + 1 operand
310        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
311        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
312        SetOperandValue(mir->ssa_rep->defs[0], res);
313      }
314      break;
315
316    case Instruction::LONG_TO_FLOAT:
317    case Instruction::LONG_TO_INT:
318    case Instruction::DOUBLE_TO_FLOAT:
319    case Instruction::DOUBLE_TO_INT: {
320        // res = op + 1 wide operand
321        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
322        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
323        SetOperandValue(mir->ssa_rep->defs[0], res);
324      }
325      break;
326
327
328    case Instruction::DOUBLE_TO_LONG:
329    case Instruction::LONG_TO_DOUBLE:
330    case Instruction::NEG_LONG:
331    case Instruction::NOT_LONG:
332    case Instruction::NEG_DOUBLE: {
333        // wide res = op + 1 wide operand
334        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
335        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
336        SetOperandValueWide(mir->ssa_rep->defs[0], res);
337      }
338      break;
339
340    case Instruction::FLOAT_TO_DOUBLE:
341    case Instruction::FLOAT_TO_LONG:
342    case Instruction::INT_TO_DOUBLE:
343    case Instruction::INT_TO_LONG: {
344        // wide res = op + 1 operand
345        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
346        res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
347        SetOperandValueWide(mir->ssa_rep->defs[0], res);
348      }
349      break;
350
351    case Instruction::CMPL_DOUBLE:
352    case Instruction::CMPG_DOUBLE:
353    case Instruction::CMP_LONG: {
354        // res = op + 2 wide operands
355        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
356        uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
357        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
358        SetOperandValue(mir->ssa_rep->defs[0], res);
359      }
360      break;
361
362    case Instruction::CMPG_FLOAT:
363    case Instruction::CMPL_FLOAT:
364    case Instruction::ADD_INT:
365    case Instruction::ADD_INT_2ADDR:
366    case Instruction::MUL_INT:
367    case Instruction::MUL_INT_2ADDR:
368    case Instruction::AND_INT:
369    case Instruction::AND_INT_2ADDR:
370    case Instruction::OR_INT:
371    case Instruction::OR_INT_2ADDR:
372    case Instruction::XOR_INT:
373    case Instruction::XOR_INT_2ADDR:
374    case Instruction::SUB_INT:
375    case Instruction::SUB_INT_2ADDR:
376    case Instruction::DIV_INT:
377    case Instruction::DIV_INT_2ADDR:
378    case Instruction::REM_INT:
379    case Instruction::REM_INT_2ADDR:
380    case Instruction::SHL_INT:
381    case Instruction::SHL_INT_2ADDR:
382    case Instruction::SHR_INT:
383    case Instruction::SHR_INT_2ADDR:
384    case Instruction::USHR_INT:
385    case Instruction::USHR_INT_2ADDR: {
386        // res = op + 2 operands
387        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
388        uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
389        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
390        SetOperandValue(mir->ssa_rep->defs[0], res);
391      }
392      break;
393
394    case Instruction::ADD_LONG:
395    case Instruction::SUB_LONG:
396    case Instruction::MUL_LONG:
397    case Instruction::DIV_LONG:
398    case Instruction::REM_LONG:
399    case Instruction::AND_LONG:
400    case Instruction::OR_LONG:
401    case Instruction::XOR_LONG:
402    case Instruction::ADD_LONG_2ADDR:
403    case Instruction::SUB_LONG_2ADDR:
404    case Instruction::MUL_LONG_2ADDR:
405    case Instruction::DIV_LONG_2ADDR:
406    case Instruction::REM_LONG_2ADDR:
407    case Instruction::AND_LONG_2ADDR:
408    case Instruction::OR_LONG_2ADDR:
409    case Instruction::XOR_LONG_2ADDR:
410    case Instruction::ADD_DOUBLE:
411    case Instruction::SUB_DOUBLE:
412    case Instruction::MUL_DOUBLE:
413    case Instruction::DIV_DOUBLE:
414    case Instruction::REM_DOUBLE:
415    case Instruction::ADD_DOUBLE_2ADDR:
416    case Instruction::SUB_DOUBLE_2ADDR:
417    case Instruction::MUL_DOUBLE_2ADDR:
418    case Instruction::DIV_DOUBLE_2ADDR:
419    case Instruction::REM_DOUBLE_2ADDR: {
420        // wide res = op + 2 wide operands
421        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
422        uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
423        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
424        SetOperandValueWide(mir->ssa_rep->defs[0], res);
425      }
426      break;
427
428    case Instruction::SHL_LONG:
429    case Instruction::SHR_LONG:
430    case Instruction::USHR_LONG:
431    case Instruction::SHL_LONG_2ADDR:
432    case Instruction::SHR_LONG_2ADDR:
433    case Instruction::USHR_LONG_2ADDR: {
434        // wide res = op + 1 wide operand + 1 operand
435        uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
436        uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
437        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
438        SetOperandValueWide(mir->ssa_rep->defs[0], res);
439      }
440      break;
441
442    case Instruction::ADD_FLOAT:
443    case Instruction::SUB_FLOAT:
444    case Instruction::MUL_FLOAT:
445    case Instruction::DIV_FLOAT:
446    case Instruction::REM_FLOAT:
447    case Instruction::ADD_FLOAT_2ADDR:
448    case Instruction::SUB_FLOAT_2ADDR:
449    case Instruction::MUL_FLOAT_2ADDR:
450    case Instruction::DIV_FLOAT_2ADDR:
451    case Instruction::REM_FLOAT_2ADDR: {
452        // res = op + 2 operands
453        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
454        uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
455        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
456        SetOperandValue(mir->ssa_rep->defs[0], res);
457      }
458      break;
459
460    case Instruction::RSUB_INT:
461    case Instruction::ADD_INT_LIT16:
462    case Instruction::MUL_INT_LIT16:
463    case Instruction::DIV_INT_LIT16:
464    case Instruction::REM_INT_LIT16:
465    case Instruction::AND_INT_LIT16:
466    case Instruction::OR_INT_LIT16:
467    case Instruction::XOR_INT_LIT16:
468    case Instruction::ADD_INT_LIT8:
469    case Instruction::RSUB_INT_LIT8:
470    case Instruction::MUL_INT_LIT8:
471    case Instruction::DIV_INT_LIT8:
472    case Instruction::REM_INT_LIT8:
473    case Instruction::AND_INT_LIT8:
474    case Instruction::OR_INT_LIT8:
475    case Instruction::XOR_INT_LIT8:
476    case Instruction::SHL_INT_LIT8:
477    case Instruction::SHR_INT_LIT8:
478    case Instruction::USHR_INT_LIT8: {
479        // Same as res = op + 2 operands, except use vB as operand 2
480        uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
481        uint16_t operand2 = LookupValue(Instruction::CONST, mir->dalvikInsn.vB, 0, 0);
482        res = LookupValue(opcode, operand1, operand2, NO_VALUE);
483        SetOperandValue(mir->ssa_rep->defs[0], res);
484      }
485      break;
486
487    case Instruction::AGET_OBJECT:
488    case Instruction::AGET:
489    case Instruction::AGET_WIDE:
490    case Instruction::AGET_BOOLEAN:
491    case Instruction::AGET_BYTE:
492    case Instruction::AGET_CHAR:
493    case Instruction::AGET_SHORT: {
494        uint16_t type = opcode - Instruction::AGET;
495        uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
496        HandleNullCheck(mir, array);
497        uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
498        HandleRangeCheck(mir, array, index);
499        // Establish value number for loaded register. Note use of memory version.
500        uint16_t memory_version = GetMemoryVersion(array, NO_VALUE, type);
501        uint16_t res = LookupValue(ARRAY_REF, array, index, memory_version);
502        if (opcode == Instruction::AGET_WIDE) {
503          SetOperandValueWide(mir->ssa_rep->defs[0], res);
504        } else {
505          SetOperandValue(mir->ssa_rep->defs[0], res);
506        }
507      }
508      break;
509
510    case Instruction::APUT_OBJECT:
511      HandlePutObject(mir);
512      // Intentional fall-through.
513    case Instruction::APUT:
514    case Instruction::APUT_WIDE:
515    case Instruction::APUT_BYTE:
516    case Instruction::APUT_BOOLEAN:
517    case Instruction::APUT_SHORT:
518    case Instruction::APUT_CHAR: {
519        uint16_t type = opcode - Instruction::APUT;
520        int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
521        int index_idx = array_idx + 1;
522        uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
523        HandleNullCheck(mir, array);
524        uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
525        HandleRangeCheck(mir, array, index);
526        // Rev the memory version
527        AdvanceMemoryVersion(array, NO_VALUE, type);
528      }
529      break;
530
531    case Instruction::IGET_OBJECT:
532    case Instruction::IGET:
533    case Instruction::IGET_WIDE:
534    case Instruction::IGET_BOOLEAN:
535    case Instruction::IGET_BYTE:
536    case Instruction::IGET_CHAR:
537    case Instruction::IGET_SHORT: {
538        uint16_t type = opcode - Instruction::IGET;
539        uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
540        HandleNullCheck(mir, base);
541        const IFieldAnnotation& annotation = cu_->mir_graph->GetIFieldAnnotation(mir);
542        uint16_t memory_version;
543        uint16_t field_id;
544        if (annotation.IsVolatile()) {
545          // Volatile fields always get a new memory version; field id is irrelevant.
546          // Unresolved fields are always marked as volatile and handled the same way here.
547          field_id = 0u;
548          memory_version = next_memory_version_;
549          ++next_memory_version_;
550        } else {
551          DCHECK(annotation.IsResolved());
552          field_id = GetFieldId(annotation.DeclaringDexFile(), annotation.DeclaringFieldIndex());
553          memory_version = std::max(unresolved_ifield_version_[type],
554                                    GetMemoryVersion(base, field_id, type));
555        }
556        if (opcode == Instruction::IGET_WIDE) {
557          res = LookupValue(Instruction::IGET_WIDE, base, field_id, memory_version);
558          SetOperandValueWide(mir->ssa_rep->defs[0], res);
559        } else {
560          res = LookupValue(Instruction::IGET, base, field_id, memory_version);
561          SetOperandValue(mir->ssa_rep->defs[0], res);
562        }
563      }
564      break;
565
566    case Instruction::IPUT_OBJECT:
567      HandlePutObject(mir);
568      // Intentional fall-through.
569    case Instruction::IPUT:
570    case Instruction::IPUT_WIDE:
571    case Instruction::IPUT_BOOLEAN:
572    case Instruction::IPUT_BYTE:
573    case Instruction::IPUT_CHAR:
574    case Instruction::IPUT_SHORT: {
575        uint16_t type = opcode - Instruction::IPUT;
576        int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
577        uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
578        HandleNullCheck(mir, base);
579        const IFieldAnnotation& annotation = cu_->mir_graph->GetIFieldAnnotation(mir);
580        if (!annotation.IsResolved()) {
581          // Unresolved fields always alias with everything of the same type.
582          unresolved_ifield_version_[type] = next_memory_version_;
583          ++next_memory_version_;
584        } else if (annotation.IsVolatile()) {
585          // Nothing to do, resolved volatile fields always get a new memory version anyway and
586          // can't alias with resolved non-volatile fields.
587        } else {
588          AdvanceMemoryVersion(base, GetFieldId(annotation.DeclaringDexFile(),
589                                                annotation.DeclaringFieldIndex()), type);
590        }
591      }
592      break;
593
594    case Instruction::SGET_OBJECT:
595    case Instruction::SGET:
596    case Instruction::SGET_WIDE:
597    case Instruction::SGET_BOOLEAN:
598    case Instruction::SGET_BYTE:
599    case Instruction::SGET_CHAR:
600    case Instruction::SGET_SHORT: {
601        uint16_t type = opcode - Instruction::SGET;
602        const SFieldAnnotation& annotation = cu_->mir_graph->GetSFieldAnnotation(mir);
603        uint16_t memory_version;
604        uint16_t field_id;
605        if (annotation.IsVolatile()) {
606          // Volatile fields always get a new memory version; field id is irrelevant.
607          // Unresolved fields are always marked as volatile and handled the same way here.
608          field_id = 0u;
609          memory_version = next_memory_version_;
610          ++next_memory_version_;
611        } else {
612          DCHECK(annotation.IsResolved());
613          field_id = GetFieldId(annotation.DeclaringDexFile(), annotation.DeclaringFieldIndex());
614          memory_version = std::max(unresolved_sfield_version_[type],
615                                    GetMemoryVersion(NO_VALUE, field_id, type));
616        }
617        if (opcode == Instruction::SGET_WIDE) {
618          res = LookupValue(Instruction::SGET_WIDE, NO_VALUE, field_id, memory_version);
619          SetOperandValueWide(mir->ssa_rep->defs[0], res);
620        } else {
621          res = LookupValue(Instruction::SGET, NO_VALUE, field_id, memory_version);
622          SetOperandValue(mir->ssa_rep->defs[0], res);
623        }
624      }
625      break;
626
627    case Instruction::SPUT_OBJECT:
628      HandlePutObject(mir);
629      // Intentional fall-through.
630    case Instruction::SPUT:
631    case Instruction::SPUT_WIDE:
632    case Instruction::SPUT_BOOLEAN:
633    case Instruction::SPUT_BYTE:
634    case Instruction::SPUT_CHAR:
635    case Instruction::SPUT_SHORT: {
636        uint16_t type = opcode - Instruction::SPUT;
637        const SFieldAnnotation& annotation = cu_->mir_graph->GetSFieldAnnotation(mir);
638        if (!annotation.IsResolved()) {
639          // Unresolved fields always alias with everything of the same type.
640          unresolved_sfield_version_[type] = next_memory_version_;
641          ++next_memory_version_;
642        } else if (annotation.IsVolatile()) {
643          // Nothing to do, resolved volatile fields always get a new memory version anyway and
644          // can't alias with resolved non-volatile fields.
645        } else {
646          AdvanceMemoryVersion(NO_VALUE, GetFieldId(annotation.DeclaringDexFile(),
647                                                    annotation.DeclaringFieldIndex()), type);
648        }
649      }
650      break;
651  }
652  return res;
653}
654
655}    // namespace art
656