summaryrefslogtreecommitdiff
path: root/compiler/dex/local_value_numbering.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/local_value_numbering.cc')
-rw-r--r--compiler/dex/local_value_numbering.cc401
1 files changed, 272 insertions, 129 deletions
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index 9e83210012..13846433b9 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -16,8 +16,121 @@
#include "local_value_numbering.h"
+#include "mir_annotations.h"
+#include "mir_graph.h"
+
namespace art {
+uint16_t LocalValueNumbering::GetFieldId(const DexFile* dex_file, uint16_t field_idx) {
+ FieldReference key = { dex_file, field_idx };
+ auto it = field_index_map_.find(key);
+ if (it != field_index_map_.end()) {
+ return it->second;
+ }
+ uint16_t id = field_index_map_.size();
+ field_index_map_.Put(key, id);
+ return id;
+}
+
+void LocalValueNumbering::AdvanceGlobalMemory() {
+ // See AdvanceMemoryVersion() for explanation.
+ global_memory_version_ = next_memory_version_;
+ ++next_memory_version_;
+}
+
+uint16_t LocalValueNumbering::GetMemoryVersion(uint16_t base, uint16_t field, uint16_t type) {
+ // See AdvanceMemoryVersion() for explanation.
+ MemoryVersionKey key = { base, field, type };
+ MemoryVersionMap::iterator it = memory_version_map_.find(key);
+ uint16_t memory_version = (it != memory_version_map_.end()) ? it->second : 0u;
+ if (base != NO_VALUE && non_aliasing_refs_.find(base) == non_aliasing_refs_.end()) {
+ // Check modifications by potentially aliased access.
+ MemoryVersionKey aliased_access_key = { NO_VALUE, field, type };
+ auto aa_it = memory_version_map_.find(aliased_access_key);
+ if (aa_it != memory_version_map_.end() && aa_it->second > memory_version) {
+ memory_version = aa_it->second;
+ }
+ memory_version = std::max(memory_version, global_memory_version_);
+ } else if (base != NO_VALUE) {
+ // Ignore global_memory_version_ for access via unique references.
+ } else {
+ memory_version = std::max(memory_version, global_memory_version_);
+ }
+ return memory_version;
+};
+
+uint16_t LocalValueNumbering::AdvanceMemoryVersion(uint16_t base, uint16_t field, uint16_t type) {
+ // When we read the same value from memory, we want to assign the same value name to it.
+ // However, we need to be careful not to assign the same value name if the memory location
+ // may have been written to between the reads. To avoid that we do "memory versioning".
+ //
+ // For each write to a memory location (instance field, static field, array element) we assign
+ // a new memory version number to the location identified by the value name of the base register,
+ // the field id and type, or "{ base, field, type }". For static fields the "base" is NO_VALUE
+ // since they are not accessed via a reference. For arrays the "field" is NO_VALUE since they
+ // don't have a field id.
+ //
+ // To account for the possibility of aliased access to the same memory location via different
+ // "base", we also store the memory version number with the key "{ NO_VALUE, field, type }"
+ // if "base" is an aliasing reference and check it in GetMemoryVersion() on reads via
+ // aliasing references. A global memory version is set for method calls as a method can
+ // potentially write to any memory location accessed via an aliasing reference.
+
+ uint16_t result = next_memory_version_;
+ ++next_memory_version_;
+ MemoryVersionKey key = { base, field, type };
+ memory_version_map_.Overwrite(key, result);
+ if (base != NO_VALUE && non_aliasing_refs_.find(base) == non_aliasing_refs_.end()) {
+ // Advance memory version for aliased access.
+ MemoryVersionKey aliased_access_key = { NO_VALUE, field, type };
+ memory_version_map_.Overwrite(aliased_access_key, result);
+ }
+ return result;
+};
+
+uint16_t LocalValueNumbering::MarkNonAliasingNonNull(MIR* mir) {
+ uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
+ SetOperandValue(mir->ssa_rep->defs[0], res);
+ DCHECK(null_checked_.find(res) == null_checked_.end());
+ null_checked_.insert(res);
+ non_aliasing_refs_.insert(res);
+ return res;
+}
+
+void LocalValueNumbering::MakeArgsAliasing(MIR* mir) {
+ for (size_t i = 0u, count = mir->ssa_rep->num_uses; i != count; ++i) {
+ uint16_t reg = GetOperandValue(mir->ssa_rep->uses[i]);
+ non_aliasing_refs_.erase(reg);
+ }
+}
+
+void LocalValueNumbering::HandleNullCheck(MIR* mir, uint16_t reg) {
+ if (null_checked_.find(reg) != null_checked_.end()) {
+ if (cu_->verbose) {
+ LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
+ }
+ mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
+ } else {
+ null_checked_.insert(reg);
+ }
+}
+
+void LocalValueNumbering::HandleRangeCheck(MIR* mir, uint16_t array, uint16_t index) {
+ if (ValueExists(ARRAY_REF, array, index, NO_VALUE)) {
+ if (cu_->verbose) {
+ LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
+ }
+ mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
+ }
+ // Use side effect to note range check completed.
+ (void)LookupValue(ARRAY_REF, array, index, NO_VALUE);
+}
+
+void LocalValueNumbering::HandlePutObject(MIR* mir) {
+ // If we're storing a non-aliasing reference, stop tracking it as non-aliasing now.
+ uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
+ non_aliasing_refs_.erase(base);
+}
uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
uint16_t res = NO_VALUE;
@@ -36,8 +149,6 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::CHECK_CAST:
case Instruction::THROW:
case Instruction::FILL_ARRAY_DATA:
- case Instruction::FILLED_NEW_ARRAY:
- case Instruction::FILLED_NEW_ARRAY_RANGE:
case Instruction::PACKED_SWITCH:
case Instruction::SPARSE_SWITCH:
case Instruction::IF_EQ:
@@ -52,8 +163,24 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::IF_GEZ:
case Instruction::IF_GTZ:
case Instruction::IF_LEZ:
- case Instruction::INVOKE_STATIC_RANGE:
- case Instruction::INVOKE_STATIC:
+ case kMirOpFusedCmplFloat:
+ case kMirOpFusedCmpgFloat:
+ case kMirOpFusedCmplDouble:
+ case kMirOpFusedCmpgDouble:
+ case kMirOpFusedCmpLong:
+ // Nothing defined - take no action.
+ break;
+
+ case Instruction::FILLED_NEW_ARRAY:
+ case Instruction::FILLED_NEW_ARRAY_RANGE:
+ // Nothing defined but the result will be unique and non-null.
+ if (mir->next != nullptr && mir->next->dalvikInsn.opcode == Instruction::MOVE_RESULT_OBJECT) {
+ MarkNonAliasingNonNull(mir->next);
+ // The MOVE_RESULT_OBJECT will be processed next and we'll return the value name then.
+ }
+ MakeArgsAliasing(mir);
+ break;
+
case Instruction::INVOKE_DIRECT:
case Instruction::INVOKE_DIRECT_RANGE:
case Instruction::INVOKE_VIRTUAL:
@@ -61,34 +188,38 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::INVOKE_SUPER:
case Instruction::INVOKE_SUPER_RANGE:
case Instruction::INVOKE_INTERFACE:
- case Instruction::INVOKE_INTERFACE_RANGE:
- case kMirOpFusedCmplFloat:
- case kMirOpFusedCmpgFloat:
- case kMirOpFusedCmplDouble:
- case kMirOpFusedCmpgDouble:
- case kMirOpFusedCmpLong:
- // Nothing defined - take no action.
+ case Instruction::INVOKE_INTERFACE_RANGE: {
+ // Nothing defined but handle the null check.
+ uint16_t reg = GetOperandValue(mir->ssa_rep->uses[0]);
+ HandleNullCheck(mir, reg);
+ }
+ // Intentional fall-through.
+ case Instruction::INVOKE_STATIC:
+ case Instruction::INVOKE_STATIC_RANGE:
+ AdvanceGlobalMemory();
+ MakeArgsAliasing(mir);
break;
- case Instruction::MOVE_EXCEPTION:
case Instruction::MOVE_RESULT:
case Instruction::MOVE_RESULT_OBJECT:
case Instruction::INSTANCE_OF:
+ // 1 result, treat as unique each time, use result s_reg - will be unique.
+ res = GetOperandValue(mir->ssa_rep->defs[0]);
+ SetOperandValue(mir->ssa_rep->defs[0], res);
+ break;
+ case Instruction::MOVE_EXCEPTION:
case Instruction::NEW_INSTANCE:
case Instruction::CONST_STRING:
case Instruction::CONST_STRING_JUMBO:
case Instruction::CONST_CLASS:
- case Instruction::NEW_ARRAY: {
- // 1 result, treat as unique each time, use result s_reg - will be unique.
- uint16_t res = GetOperandValue(mir->ssa_rep->defs[0]);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
+ case Instruction::NEW_ARRAY:
+ // 1 result, treat as unique each time, use result s_reg - will be unique.
+ res = MarkNonAliasingNonNull(mir);
break;
- case Instruction::MOVE_RESULT_WIDE: {
- // 1 wide result, treat as unique each time, use result s_reg - will be unique.
- uint16_t res = GetOperandValueWide(mir->ssa_rep->defs[0]);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- }
+ case Instruction::MOVE_RESULT_WIDE:
+ // 1 wide result, treat as unique each time, use result s_reg - will be unique.
+ res = GetOperandValueWide(mir->ssa_rep->defs[0]);
+ SetOperandValueWide(mir->ssa_rep->defs[0], res);
break;
case kMirOpPhi:
@@ -104,35 +235,31 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::MOVE_OBJECT_16:
case Instruction::MOVE_FROM16:
case Instruction::MOVE_OBJECT_FROM16:
- case kMirOpCopy: {
- // Just copy value number of source to value number of resulit.
- uint16_t res = GetOperandValue(mir->ssa_rep->uses[0]);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
+ case kMirOpCopy:
+ // Just copy value number of source to value number of result.
+ res = GetOperandValue(mir->ssa_rep->uses[0]);
+ SetOperandValue(mir->ssa_rep->defs[0], res);
break;
case Instruction::MOVE_WIDE:
case Instruction::MOVE_WIDE_16:
- case Instruction::MOVE_WIDE_FROM16: {
- // Just copy value number of source to value number of result.
- uint16_t res = GetOperandValueWide(mir->ssa_rep->uses[0]);
- SetOperandValueWide(mir->ssa_rep->defs[0], res);
- }
+ case Instruction::MOVE_WIDE_FROM16:
+ // Just copy value number of source to value number of result.
+ res = GetOperandValueWide(mir->ssa_rep->uses[0]);
+ SetOperandValueWide(mir->ssa_rep->defs[0], res);
break;
case Instruction::CONST:
case Instruction::CONST_4:
- case Instruction::CONST_16: {
- uint16_t res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
- High16Bits(mir->dalvikInsn.vB >> 16), 0);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
+ case Instruction::CONST_16:
+ res = LookupValue(Instruction::CONST, Low16Bits(mir->dalvikInsn.vB),
+ High16Bits(mir->dalvikInsn.vB >> 16), 0);
+ SetOperandValue(mir->ssa_rep->defs[0], res);
break;
- case Instruction::CONST_HIGH16: {
- uint16_t res = LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
- SetOperandValue(mir->ssa_rep->defs[0], res);
- }
+ case Instruction::CONST_HIGH16:
+ res = LookupValue(Instruction::CONST, 0, mir->dalvikInsn.vB, 0);
+ SetOperandValue(mir->ssa_rep->defs[0], res);
break;
case Instruction::CONST_WIDE_16:
@@ -145,8 +272,8 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
} else {
high_res = LookupValue(Instruction::CONST, 0, 0, 2);
}
- uint16_t res = LookupValue(Instruction::CONST, low_res, high_res, 3);
- SetOperandValue(mir->ssa_rep->defs[0], res);
+ res = LookupValue(Instruction::CONST, low_res, high_res, 3);
+ SetOperandValueWide(mir->ssa_rep->defs[0], res);
}
break;
@@ -157,7 +284,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
High16Bits(low_word), 1);
uint16_t high_res = LookupValue(Instruction::CONST, Low16Bits(high_word),
High16Bits(high_word), 2);
- uint16_t res = LookupValue(Instruction::CONST, low_res, high_res, 3);
+ res = LookupValue(Instruction::CONST, low_res, high_res, 3);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
}
break;
@@ -165,7 +292,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::CONST_WIDE_HIGH16: {
uint16_t low_res = LookupValue(Instruction::CONST, 0, 0, 1);
uint16_t high_res = LookupValue(Instruction::CONST, 0, Low16Bits(mir->dalvikInsn.vB), 2);
- uint16_t res = LookupValue(Instruction::CONST, low_res, high_res, 3);
+ res = LookupValue(Instruction::CONST, low_res, high_res, 3);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
}
break;
@@ -181,7 +308,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::FLOAT_TO_INT: {
// res = op + 1 operand
uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
- uint16_t res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
+ res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
break;
@@ -192,7 +319,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::DOUBLE_TO_INT: {
// res = op + 1 wide operand
uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
- uint16_t res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
+ res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
break;
@@ -205,7 +332,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::NEG_DOUBLE: {
// wide res = op + 1 wide operand
uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
- uint16_t res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
+ res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
}
break;
@@ -216,7 +343,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
case Instruction::INT_TO_LONG: {
// wide res = op + 1 operand
uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
- uint16_t res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
+ res = LookupValue(opcode, operand1, NO_VALUE, NO_VALUE);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
}
break;
@@ -227,7 +354,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
// res = op + 2 wide operands
uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
- uint16_t res = LookupValue(opcode, operand1, operand2, NO_VALUE);
+ res = LookupValue(opcode, operand1, operand2, NO_VALUE);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
break;
@@ -259,7 +386,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
// res = op + 2 operands
uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
- uint16_t res = LookupValue(opcode, operand1, operand2, NO_VALUE);
+ res = LookupValue(opcode, operand1, operand2, NO_VALUE);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
break;
@@ -293,7 +420,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
// wide res = op + 2 wide operands
uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
- uint16_t res = LookupValue(opcode, operand1, operand2, NO_VALUE);
+ res = LookupValue(opcode, operand1, operand2, NO_VALUE);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
}
break;
@@ -307,7 +434,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
// wide res = op + 1 wide operand + 1 operand
uint16_t operand1 = GetOperandValueWide(mir->ssa_rep->uses[0]);
uint16_t operand2 = GetOperandValueWide(mir->ssa_rep->uses[2]);
- uint16_t res = LookupValue(opcode, operand1, operand2, NO_VALUE);
+ res = LookupValue(opcode, operand1, operand2, NO_VALUE);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
}
break;
@@ -325,7 +452,7 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
// res = op + 2 operands
uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
uint16_t operand2 = GetOperandValue(mir->ssa_rep->uses[1]);
- uint16_t res = LookupValue(opcode, operand1, operand2, NO_VALUE);
+ res = LookupValue(opcode, operand1, operand2, NO_VALUE);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
break;
@@ -352,38 +479,25 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
// Same as res = op + 2 operands, except use vB as operand 2
uint16_t operand1 = GetOperandValue(mir->ssa_rep->uses[0]);
uint16_t operand2 = LookupValue(Instruction::CONST, mir->dalvikInsn.vB, 0, 0);
- uint16_t res = LookupValue(opcode, operand1, operand2, NO_VALUE);
+ res = LookupValue(opcode, operand1, operand2, NO_VALUE);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
break;
- case Instruction::AGET_WIDE:
- case Instruction::AGET:
case Instruction::AGET_OBJECT:
+ case Instruction::AGET:
+ case Instruction::AGET_WIDE:
case Instruction::AGET_BOOLEAN:
case Instruction::AGET_BYTE:
case Instruction::AGET_CHAR:
case Instruction::AGET_SHORT: {
+ uint16_t type = opcode - Instruction::AGET;
uint16_t array = GetOperandValue(mir->ssa_rep->uses[0]);
- if (null_checked_.find(array) != null_checked_.end()) {
- if (cu_->verbose) {
- LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
- } else {
- null_checked_.insert(array);
- }
+ HandleNullCheck(mir, array);
uint16_t index = GetOperandValue(mir->ssa_rep->uses[1]);
- if (ValueExists(ARRAY_REF, array, index, NO_VALUE)) {
- if (cu_->verbose) {
- LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
- }
- // Use side effect to note range check completed.
- (void)LookupValue(ARRAY_REF, array, index, NO_VALUE);
+ HandleRangeCheck(mir, array, index);
// Establish value number for loaded register. Note use of memory version.
- uint16_t memory_version = GetMemoryVersion(array, NO_VALUE);
+ uint16_t memory_version = GetMemoryVersion(array, NO_VALUE, type);
uint16_t res = LookupValue(ARRAY_REF, array, index, memory_version);
if (opcode == Instruction::AGET_WIDE) {
SetOperandValueWide(mir->ssa_rep->defs[0], res);
@@ -393,116 +507,145 @@ uint16_t LocalValueNumbering::GetValueNumber(MIR* mir) {
}
break;
- case Instruction::APUT_WIDE:
- case Instruction::APUT:
case Instruction::APUT_OBJECT:
- case Instruction::APUT_SHORT:
- case Instruction::APUT_CHAR:
+ HandlePutObject(mir);
+ // Intentional fall-through.
+ case Instruction::APUT:
+ case Instruction::APUT_WIDE:
case Instruction::APUT_BYTE:
- case Instruction::APUT_BOOLEAN: {
+ case Instruction::APUT_BOOLEAN:
+ case Instruction::APUT_SHORT:
+ case Instruction::APUT_CHAR: {
+ uint16_t type = opcode - Instruction::APUT;
int array_idx = (opcode == Instruction::APUT_WIDE) ? 2 : 1;
int index_idx = array_idx + 1;
uint16_t array = GetOperandValue(mir->ssa_rep->uses[array_idx]);
- if (null_checked_.find(array) != null_checked_.end()) {
- if (cu_->verbose) {
- LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
- } else {
- null_checked_.insert(array);
- }
+ HandleNullCheck(mir, array);
uint16_t index = GetOperandValue(mir->ssa_rep->uses[index_idx]);
- if (ValueExists(ARRAY_REF, array, index, NO_VALUE)) {
- if (cu_->verbose) {
- LOG(INFO) << "Removing range check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_RANGE_CHECK;
- }
- // Use side effect to note range check completed.
- (void)LookupValue(ARRAY_REF, array, index, NO_VALUE);
+ HandleRangeCheck(mir, array, index);
// Rev the memory version
- AdvanceMemoryVersion(array, NO_VALUE);
+ AdvanceMemoryVersion(array, NO_VALUE, type);
}
break;
case Instruction::IGET_OBJECT:
- case Instruction::IGET_WIDE:
case Instruction::IGET:
- case Instruction::IGET_CHAR:
- case Instruction::IGET_SHORT:
+ case Instruction::IGET_WIDE:
case Instruction::IGET_BOOLEAN:
- case Instruction::IGET_BYTE: {
+ case Instruction::IGET_BYTE:
+ case Instruction::IGET_CHAR:
+ case Instruction::IGET_SHORT: {
+ uint16_t type = opcode - Instruction::IGET;
uint16_t base = GetOperandValue(mir->ssa_rep->uses[0]);
- if (null_checked_.find(base) != null_checked_.end()) {
- if (cu_->verbose) {
- LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
+ HandleNullCheck(mir, base);
+ const IFieldAnnotation& annotation = cu_->mir_graph->GetIFieldAnnotation(mir);
+ uint16_t memory_version;
+ uint16_t field_id;
+ if (annotation.IsVolatile()) {
+ // Volatile fields always get a new memory version; field id is irrelevant.
+ // Unresolved fields are always marked as volatile and handled the same way here.
+ field_id = 0u;
+ memory_version = next_memory_version_;
+ ++next_memory_version_;
} else {
- null_checked_.insert(base);
+ DCHECK(annotation.IsResolved());
+ field_id = GetFieldId(annotation.DeclaringDexFile(), annotation.DeclaringFieldIndex());
+ memory_version = std::max(unresolved_ifield_version_[type],
+ GetMemoryVersion(base, field_id, type));
}
- uint16_t field_ref = mir->dalvikInsn.vC;
- uint16_t memory_version = GetMemoryVersion(base, field_ref);
if (opcode == Instruction::IGET_WIDE) {
- uint16_t res = LookupValue(Instruction::IGET_WIDE, base, field_ref, memory_version);
+ res = LookupValue(Instruction::IGET_WIDE, base, field_id, memory_version);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
} else {
- uint16_t res = LookupValue(Instruction::IGET, base, field_ref, memory_version);
+ res = LookupValue(Instruction::IGET, base, field_id, memory_version);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
}
break;
- case Instruction::IPUT_WIDE:
case Instruction::IPUT_OBJECT:
+ HandlePutObject(mir);
+ // Intentional fall-through.
case Instruction::IPUT:
+ case Instruction::IPUT_WIDE:
case Instruction::IPUT_BOOLEAN:
case Instruction::IPUT_BYTE:
case Instruction::IPUT_CHAR:
case Instruction::IPUT_SHORT: {
+ uint16_t type = opcode - Instruction::IPUT;
int base_reg = (opcode == Instruction::IPUT_WIDE) ? 2 : 1;
uint16_t base = GetOperandValue(mir->ssa_rep->uses[base_reg]);
- if (null_checked_.find(base) != null_checked_.end()) {
- if (cu_->verbose) {
- LOG(INFO) << "Removing null check for 0x" << std::hex << mir->offset;
- }
- mir->optimization_flags |= MIR_IGNORE_NULL_CHECK;
+ HandleNullCheck(mir, base);
+ const IFieldAnnotation& annotation = cu_->mir_graph->GetIFieldAnnotation(mir);
+ if (!annotation.IsResolved()) {
+ // Unresolved fields always alias with everything of the same type.
+ unresolved_ifield_version_[type] = next_memory_version_;
+ ++next_memory_version_;
+ } else if (annotation.IsVolatile()) {
+ // Nothing to do, resolved volatile fields always get a new memory version anyway and
+ // can't alias with resolved non-volatile fields.
} else {
- null_checked_.insert(base);
+ AdvanceMemoryVersion(base, GetFieldId(annotation.DeclaringDexFile(),
+ annotation.DeclaringFieldIndex()), type);
}
- uint16_t field_ref = mir->dalvikInsn.vC;
- AdvanceMemoryVersion(base, field_ref);
}
break;
case Instruction::SGET_OBJECT:
case Instruction::SGET:
+ case Instruction::SGET_WIDE:
case Instruction::SGET_BOOLEAN:
case Instruction::SGET_BYTE:
case Instruction::SGET_CHAR:
- case Instruction::SGET_SHORT:
- case Instruction::SGET_WIDE: {
- uint16_t field_ref = mir->dalvikInsn.vB;
- uint16_t memory_version = GetMemoryVersion(NO_VALUE, field_ref);
+ case Instruction::SGET_SHORT: {
+ uint16_t type = opcode - Instruction::SGET;
+ const SFieldAnnotation& annotation = cu_->mir_graph->GetSFieldAnnotation(mir);
+ uint16_t memory_version;
+ uint16_t field_id;
+ if (annotation.IsVolatile()) {
+ // Volatile fields always get a new memory version; field id is irrelevant.
+ // Unresolved fields are always marked as volatile and handled the same way here.
+ field_id = 0u;
+ memory_version = next_memory_version_;
+ ++next_memory_version_;
+ } else {
+ DCHECK(annotation.IsResolved());
+ field_id = GetFieldId(annotation.DeclaringDexFile(), annotation.DeclaringFieldIndex());
+ memory_version = std::max(unresolved_sfield_version_[type],
+ GetMemoryVersion(NO_VALUE, field_id, type));
+ }
if (opcode == Instruction::SGET_WIDE) {
- uint16_t res = LookupValue(Instruction::SGET_WIDE, NO_VALUE, field_ref, memory_version);
+ res = LookupValue(Instruction::SGET_WIDE, NO_VALUE, field_id, memory_version);
SetOperandValueWide(mir->ssa_rep->defs[0], res);
} else {
- uint16_t res = LookupValue(Instruction::SGET, NO_VALUE, field_ref, memory_version);
+ res = LookupValue(Instruction::SGET, NO_VALUE, field_id, memory_version);
SetOperandValue(mir->ssa_rep->defs[0], res);
}
}
break;
case Instruction::SPUT_OBJECT:
+ HandlePutObject(mir);
+ // Intentional fall-through.
case Instruction::SPUT:
+ case Instruction::SPUT_WIDE:
case Instruction::SPUT_BOOLEAN:
case Instruction::SPUT_BYTE:
case Instruction::SPUT_CHAR:
- case Instruction::SPUT_SHORT:
- case Instruction::SPUT_WIDE: {
- uint16_t field_ref = mir->dalvikInsn.vB;
- AdvanceMemoryVersion(NO_VALUE, field_ref);
+ case Instruction::SPUT_SHORT: {
+ uint16_t type = opcode - Instruction::SPUT;
+ const SFieldAnnotation& annotation = cu_->mir_graph->GetSFieldAnnotation(mir);
+ if (!annotation.IsResolved()) {
+ // Unresolved fields always alias with everything of the same type.
+ unresolved_sfield_version_[type] = next_memory_version_;
+ ++next_memory_version_;
+ } else if (annotation.IsVolatile()) {
+ // Nothing to do, resolved volatile fields always get a new memory version anyway and
+ // can't alias with resolved non-volatile fields.
+ } else {
+ AdvanceMemoryVersion(NO_VALUE, GetFieldId(annotation.DeclaringDexFile(),
+ annotation.DeclaringFieldIndex()), type);
+ }
}
break;
}