blob: c8df326e6783b332501b4b2836eaac661f74159e [file] [log] [blame]
// Copyright (c) 2023, 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.conversion.passes;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.ArrayLength;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.passes.result.CodeRewriterResult;
import java.util.Set;
public class KnownArrayLengthRewriter extends CodeRewriterPass<AppInfo> {
public KnownArrayLengthRewriter(AppView<?> appView) {
super(appView);
}
@Override
protected String getRewriterId() {
return "KnownArrayLengthRewriter";
}
@Override
protected boolean shouldRewriteCode(IRCode code, MethodProcessor methodProcessor) {
return code.metadata().mayHaveArrayLength();
}
@Override
protected CodeRewriterResult rewriteCode(IRCode code) {
boolean hasChanged = false;
InstructionListIterator iterator = code.instructionListIterator();
while (iterator.hasNext()) {
Instruction current = iterator.next();
if (!current.isArrayLength()) {
continue;
}
ArrayLength arrayLength = current.asArrayLength();
if (arrayLength.hasOutValue() && arrayLength.outValue().hasLocalInfo()) {
continue;
}
Value array = arrayLength.array().getAliasedValue();
if (array.isPhi() || !arrayLength.array().isNeverNull() || array.hasLocalInfo()) {
continue;
}
AbstractValue abstractValue = array.getAbstractValue(appView, code.context());
if (!abstractValue.hasKnownArrayLength() && !array.isNeverNull()) {
continue;
}
Instruction arrayDefinition = array.getDefinition();
assert arrayDefinition != null;
Set<Phi> phiUsers = arrayLength.outValue().uniquePhiUsers();
if (arrayDefinition.isNewArrayEmpty()) {
Value size = arrayDefinition.asNewArrayEmpty().size();
arrayLength.outValue().replaceUsers(size);
iterator.removeOrReplaceByDebugLocalRead();
hasChanged = true;
} else if (arrayDefinition.isNewArrayFilledData()) {
long size = arrayDefinition.asNewArrayFilledData().size;
if (size > Integer.MAX_VALUE) {
continue;
}
iterator.replaceCurrentInstructionWithConstInt(code, (int) size);
hasChanged = true;
} else if (abstractValue.hasKnownArrayLength()) {
iterator.replaceCurrentInstructionWithConstInt(code, abstractValue.getKnownArrayLength());
hasChanged = true;
} else {
continue;
}
phiUsers.forEach(Phi::removeTrivialPhi);
}
if (hasChanged) {
code.removeRedundantBlocks();
}
return CodeRewriterResult.hasChanged(hasChanged);
}
}