blob: b283f96e8aca915efa544e52f04c890ac9806cda [file] [log] [blame]
// Copyright (c) 2017, 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.desugar;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import java.util.ArrayList;
import java.util.List;
// Source code representing synthesized accessor method.
final class AccessorMethodSourceCode extends SynthesizedLambdaSourceCode {
AccessorMethodSourceCode(LambdaClass lambda, Position callerPosition) {
super(
lambda, lambda.target.callTarget, callerPosition, null /* no receiver for static method */);
// We should never need an accessor for interface methods since
// they are supposed to be public.
assert !descriptor().implHandle.type.isInvokeInterface();
assert checkSignatures();
}
private boolean checkSignatures() {
DexMethodHandle implHandle = descriptor().implHandle;
assert implHandle != null;
DexType[] accessorParams = proto.parameters.values;
DexMethod implMethod = implHandle.asMethod();
DexProto implProto = implMethod.proto;
DexType[] implParams = implProto.parameters.values;
int index = 0;
if (implHandle.type.isInvokeInstance() || implHandle.type.isInvokeDirect()) {
assert accessorParams[index] == descriptor().getImplReceiverType();
index++;
}
for (DexType implParam : implParams) {
assert accessorParams[index] == implParam;
index++;
}
assert index == accessorParams.length;
assert delegatingToConstructor()
? this.proto.returnType == implMethod.holder
: this.proto.returnType == implProto.returnType;
return true;
}
// Are we delegating to a constructor?
private boolean delegatingToConstructor() {
return descriptor().implHandle.type.isInvokeConstructor();
}
private Invoke.Type inferInvokeType() {
switch (descriptor().implHandle.type) {
case INVOKE_INSTANCE:
return Invoke.Type.VIRTUAL;
case INVOKE_STATIC:
return Invoke.Type.STATIC;
case INVOKE_DIRECT:
case INVOKE_CONSTRUCTOR:
return Invoke.Type.DIRECT;
case INVOKE_INTERFACE:
throw new Unreachable("Accessor for an interface method?");
default:
throw new Unreachable();
}
}
@Override
protected void prepareInstructions() {
DexMethod implMethod = descriptor().implHandle.asMethod();
DexType[] accessorParams = proto.parameters.values;
// Prepare call arguments.
List<ValueType> argValueTypes = new ArrayList<>();
List<Integer> argRegisters = new ArrayList<>();
// If we are delegating to a constructor, we need to create the instance
// first. This instance will be the first argument to the call.
if (delegatingToConstructor()) {
int instance = nextRegister(ValueType.OBJECT);
add(builder -> builder.addNewInstance(instance, implMethod.holder));
argValueTypes.add(ValueType.OBJECT);
argRegisters.add(instance);
}
for (int i = 0; i < accessorParams.length; i++) {
DexType param = accessorParams[i];
argValueTypes.add(ValueType.fromDexType(param));
argRegisters.add(getParamRegister(i));
}
// Method call to the original impl-method.
// Mirroring assert in constructor, we never need accessors to interfaces.
assert !descriptor().implHandle.type.isInvokeInterface();
add(
builder ->
builder.addInvoke(
inferInvokeType(),
implMethod,
implMethod.proto,
argValueTypes,
argRegisters,
false /* isInterface */));
// Does the method have return value?
if (proto.returnType == factory().voidType) {
add(IRBuilder::addReturn);
} else if (delegatingToConstructor()) {
// Return newly created instance
add(builder -> builder.addReturn(argRegisters.get(0)));
} else {
ValueType valueType = ValueType.fromDexType(proto.returnType);
int tempValue = nextRegister(valueType);
add(builder -> builder.addMoveResult(tempValue));
add(builder -> builder.addReturn(tempValue));
}
}
}