blob: 36de73e6daf7199e1db8227d97e68a6d9f22bdc5 [file] [log] [blame]
// Copyright (c) 2019, 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.analysis.proto;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.InstancePut;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.ValueUtils;
import com.android.tools.r8.utils.ValueUtils.ArrayValues;
public class ProtoUtils {
public static final int IS_PROTO_2_MASK = 0x1;
@SuppressWarnings("ReferenceEquality")
public static Value getInfoValueFromMessageInfoConstructionInvoke(
InvokeMethod invoke, ProtoReferences references) {
assert references.isMessageInfoConstruction(invoke);
// First check if there is a call to the static method newMessageInfo(...).
if (invoke.getInvokedMethod().match(references.newMessageInfoMethod)) {
return invoke.getOperand(1);
}
// Otherwise, the static method has been inlined. Check if there is a call to
// RawMessageInfo.<init>(...).
assert invoke.isInvokeDirect();
if (invoke.getInvokedMethod() == references.rawMessageInfoConstructor) {
return invoke.getOperand(2);
}
// Otherwise, RawMessageInfo.<init>(...) has been inlined, and we should find a call to
// Object.<init>(). In this case, we should find an instance field assignment to
// `RawMessageInfo.info`.
assert invoke.getInvokedMethod() == references.dexItemFactory().objectMembers.constructor;
// Find the value being assigned to the `info` field.
for (InstancePut instancePut :
invoke.getFirstArgument().<InstancePut>uniqueUsers(Instruction::isInstancePut)) {
if (instancePut.getField() == references.rawMessageInfoInfoField) {
return instancePut.value();
}
}
throw new Unreachable();
}
@SuppressWarnings("ReferenceEquality")
private static Value getObjectsValueFromMessageInfoConstructionInvoke(
InvokeMethod invoke, ProtoReferences references) {
assert references.isMessageInfoConstruction(invoke);
if (invoke.getInvokedMethod().match(references.newMessageInfoMethod)) {
return invoke.getOperand(2);
}
assert invoke.isInvokeDirect();
if (invoke.getInvokedMethod() == references.rawMessageInfoConstructor) {
return invoke.getOperand(3);
}
assert invoke.getInvokedMethod() == references.dexItemFactory().objectMembers.constructor;
// Find the value being assigned to the `info` field.
for (InstancePut instancePut :
invoke.getFirstArgument().<InstancePut>uniqueUsers(Instruction::isInstancePut)) {
if (instancePut.getField() == references.rawMessageInfoObjectsField) {
return instancePut.value();
}
}
throw new Unreachable();
}
static ArrayValues getObjectsArrayValuesFromMessageInfoConstructionInvoke(
InvokeMethod invoke, ProtoReferences references) {
Value arrayValue = getObjectsValueFromMessageInfoConstructionInvoke(invoke, references);
return ValueUtils.computeSingleUseArrayValues(arrayValue, invoke);
}
@SuppressWarnings("ReferenceEquality")
static void setObjectsValueForMessageInfoConstructionInvoke(
InvokeMethod invoke, Value newObjectsValue, ProtoReferences references) {
assert references.isMessageInfoConstruction(invoke);
if (invoke.getInvokedMethod().match(references.newMessageInfoMethod)) {
invoke.replaceValue(2, newObjectsValue);
return;
}
assert invoke.isInvokeDirect();
if (invoke.getInvokedMethod() == references.rawMessageInfoConstructor) {
invoke.replaceValue(3, newObjectsValue);
return;
}
assert invoke.getInvokedMethod() == references.dexItemFactory().objectMembers.constructor;
// Find the value being assigned to the `info` field.
for (InstancePut instancePut :
invoke.getFirstArgument().<InstancePut>uniqueUsers(Instruction::isInstancePut)) {
if (instancePut.getField() == references.rawMessageInfoObjectsField) {
instancePut.setValue(newObjectsValue);
return;
}
}
throw new Unreachable();
}
public static boolean isProto2(int flags) {
return (flags & IS_PROTO_2_MASK) != 0;
}
}