blob: a795308fa33676f4301731ff1264baee5a20019b [file] [log] [blame]
// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize.string;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.NumberConversion;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
public class StringBuilderHelper {
static boolean isEscapingInstructionForInValues(Instruction instruction) {
return instruction.isFieldPut()
|| instruction.isInvoke()
|| instruction.isReturn()
|| instruction.isArrayPut();
}
static boolean isEscapingInstructionForOutValues(Instruction instruction) {
return instruction.isArgument()
|| instruction.isInvoke()
|| instruction.isFieldGet()
|| instruction.isArrayGet()
|| instruction.isCheckCast();
}
static boolean canMutate(Instruction instruction) {
return instruction.isInvoke()
|| instruction.isFieldInstruction()
|| instruction.isNewInstance();
}
static boolean isInstructionThatIntroducesDefiniteAlias(
Instruction instruction, StringBuilderOracle oracle) {
return instruction.isAssume() || instruction.isCheckCast() || oracle.isAppend(instruction);
}
static String extractConstantArgument(
DexItemFactory factory, DexMethod method, Value arg, DexType argumentType) {
if (arg.isPhi()) {
return null;
}
if (arg.isConstString()) {
return arg.definition.asConstString().getValue().toString();
}
Number constantNumber = extractConstantNumber(factory, arg);
if (constantNumber == null) {
return null;
}
if (arg.getType().isPrimitiveType()) {
if (argumentType == factory.booleanType) {
return String.valueOf(constantNumber.intValue() != 0);
} else if (argumentType == factory.byteType) {
return String.valueOf(constantNumber.byteValue());
} else if (argumentType == factory.shortType) {
return String.valueOf(constantNumber.shortValue());
} else if (argumentType == factory.charType) {
return String.valueOf((char) constantNumber.intValue());
} else if (argumentType == factory.intType) {
return String.valueOf(constantNumber.intValue());
} else if (argumentType == factory.longType) {
return String.valueOf(constantNumber.longValue());
} else if (argumentType == factory.floatType) {
return String.valueOf(constantNumber.floatValue());
} else if (argumentType == factory.doubleType) {
return String.valueOf(constantNumber.doubleValue());
}
} else if (arg.getType().isNullType()
&& !method.isInstanceInitializer(factory)
&& argumentType != factory.charArrayType) {
assert constantNumber.intValue() == 0;
return "null";
}
return null;
}
static Number extractConstantNumber(DexItemFactory factory, Value arg) {
if (arg.isPhi()) {
return null;
}
if (arg.definition.isConstNumber()) {
ConstNumber cst = arg.definition.asConstNumber();
if (cst.outType() == ValueType.LONG) {
return cst.getLongValue();
} else if (cst.outType() == ValueType.FLOAT) {
return cst.getFloatValue();
} else if (cst.outType() == ValueType.DOUBLE) {
return cst.getDoubleValue();
} else {
assert cst.outType() == ValueType.INT || cst.outType() == ValueType.OBJECT;
return cst.getIntValue();
}
} else if (arg.definition.isNumberConversion()) {
NumberConversion conversion = arg.definition.asNumberConversion();
assert conversion.inValues().size() == 1;
Number temp = extractConstantNumber(factory, conversion.inValues().get(0));
if (temp == null) {
return null;
}
DexType conversionType = conversion.to.toDexType(factory);
if (conversionType == factory.booleanType) {
return temp.intValue() != 0 ? 1 : 0;
} else if (conversionType == factory.byteType) {
return temp.byteValue();
} else if (conversionType == factory.shortType) {
return temp.shortValue();
} else if (conversionType == factory.charType) {
return temp.intValue();
} else if (conversionType == factory.intType) {
return temp.intValue();
} else if (conversionType == factory.longType) {
return temp.longValue();
} else if (conversionType == factory.floatType) {
return temp.floatValue();
} else if (conversionType == factory.doubleType) {
return temp.doubleValue();
}
}
return null;
}
}