Propagate sideways conversions after an instance-of + if-eq/if-eqz

Previously, we only propagated the conversion if it was a narrowing
conversion, to avoid problems that can occur with member access with
widening conversions.

However, it should be safe to do the conversion for a "sideways"
conversion - one that is neither widening or narrowing.

This can happen if we don't yet have full knowledge of the register types,
or, less likely, if the "true" branch is impossible to reach.

In the first case, we should get better type info as we continue to analyze
the method, and we'll revisit the conversion once we have better type info.

Or, if it really is an impossible conversion, we still want to propagate
the type from the instance-of to the true branch.
This commit is contained in:
Ben Gruver 2017-01-07 18:04:19 -08:00
parent adb12356c3
commit 1a83d5a2d0
2 changed files with 16 additions and 9 deletions

View File

@ -374,7 +374,8 @@ public class AnalyzedInstruction implements Comparable<AnalyzedInstruction> {
if (previousInstruction != null && if (previousInstruction != null &&
previousInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF && previousInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF &&
registerNumber == ((Instruction22c)previousInstruction.instruction).getRegisterB() && registerNumber == ((Instruction22c)previousInstruction.instruction).getRegisterB() &&
MethodAnalyzer.canNarrowAfterInstanceOf(previousInstruction, this, methodAnalyzer.getClassPath())) { MethodAnalyzer.canPropogateTypeAfterInstanceOf(
previousInstruction, this, methodAnalyzer.getClassPath())) {
return true; return true;
} }
} }

View File

@ -1167,20 +1167,26 @@ public class MethodAnalyzer {
setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType); setDestinationRegisterTypeAndPropagateChanges(analyzedInstruction, castRegisterType);
} }
private static boolean isNarrowingConversion(RegisterType originalType, RegisterType newType) { private static boolean isNotWideningConversion(RegisterType originalType, RegisterType newType) {
if (originalType.type == null || newType.type == null) { if (originalType.type == null || newType.type == null) {
return false; return true;
} }
if (originalType.type.isInterface()) { if (originalType.type.isInterface()) {
return newType.type.implementsInterface(originalType.type.getType()); return newType.type.implementsInterface(originalType.type.getType());
} else { } else {
TypeProto commonSuperclass = newType.type.getCommonSuperclass(originalType.type); TypeProto commonSuperclass = newType.type.getCommonSuperclass(originalType.type);
return commonSuperclass.getType().equals(originalType.type.getType()); if (commonSuperclass.getType().equals(originalType.type.getType())) {
return true;
} }
if (commonSuperclass.getType().equals(newType.type.getType())) {
return false;
}
}
return true;
} }
static boolean canNarrowAfterInstanceOf(AnalyzedInstruction analyzedInstanceOfInstruction, static boolean canPropogateTypeAfterInstanceOf(AnalyzedInstruction analyzedInstanceOfInstruction,
AnalyzedInstruction analyzedIfInstruction, ClassPath classPath) { AnalyzedInstruction analyzedIfInstruction, ClassPath classPath) {
if (!classPath.isArt()) { if (!classPath.isArt()) {
return false; return false;
} }
@ -1197,7 +1203,7 @@ public class MethodAnalyzer {
RegisterType originalType = analyzedIfInstruction.getPreInstructionRegisterType(objectRegister); RegisterType originalType = analyzedIfInstruction.getPreInstructionRegisterType(objectRegister);
return isNarrowingConversion(originalType, registerType); return isNotWideningConversion(originalType, registerType);
} }
} catch (UnresolvedClassException ex) { } catch (UnresolvedClassException ex) {
return false; return false;
@ -1220,7 +1226,7 @@ public class MethodAnalyzer {
AnalyzedInstruction prevAnalyzedInstruction = analyzedInstruction.getPredecessors().first(); AnalyzedInstruction prevAnalyzedInstruction = analyzedInstruction.getPredecessors().first();
if (prevAnalyzedInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF) { if (prevAnalyzedInstruction.instruction.getOpcode() == Opcode.INSTANCE_OF) {
Instruction22c instanceOfInstruction = (Instruction22c)prevAnalyzedInstruction.instruction; Instruction22c instanceOfInstruction = (Instruction22c)prevAnalyzedInstruction.instruction;
if (canNarrowAfterInstanceOf(prevAnalyzedInstruction, analyzedInstruction, classPath)) { if (canPropogateTypeAfterInstanceOf(prevAnalyzedInstruction, analyzedInstruction, classPath)) {
List<Integer> narrowingRegisters = Lists.newArrayList(); List<Integer> narrowingRegisters = Lists.newArrayList();
RegisterType newType = RegisterType.getRegisterType(classPath, RegisterType newType = RegisterType.getRegisterType(classPath,
@ -1252,7 +1258,7 @@ public class MethodAnalyzer {
additionalNarrowingRegister = -1; additionalNarrowingRegister = -1;
break; break;
} }
if (isNarrowingConversion(originalType, newType)) { if (isNotWideningConversion(originalType, newType)) {
if (additionalNarrowingRegister != -1) { if (additionalNarrowingRegister != -1) {
if (additionalNarrowingRegister != moveInstruction.getRegisterB()) { if (additionalNarrowingRegister != moveInstruction.getRegisterB()) {
additionalNarrowingRegister = -1; additionalNarrowingRegister = -1;