1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// 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.DexAccessFlags;
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.MoveType;
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) {
super(lambda, lambda.target.callTarget, 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;
}
private boolean isPrivateMethod() {
// We should be able to find targets for all private impl-methods, so
// we can rely on knowing accessibility flags for them.
DexAccessFlags flags = descriptor().getAccessibility();
return flags != null && flags.isPrivate();
}
// 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<MoveType> argMoveTypes = 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(MoveType.OBJECT);
add(builder -> builder.addNewInstance(instance, implMethod.holder));
argMoveTypes.add(MoveType.OBJECT);
argRegisters.add(instance);
}
for (int i = 0; i < accessorParams.length; i++) {
DexType param = accessorParams[i];
argMoveTypes.add(MoveType.fromDexType(param));
argRegisters.add(getParamRegister(i));
}
// Method call to the original impl-method.
add(builder -> builder.addInvoke(inferInvokeType(),
implMethod, implMethod.proto, argMoveTypes, argRegisters));
// 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(MoveType.OBJECT, argRegisters.get(0)));
} else {
MoveType moveType = MoveType.fromDexType(proto.returnType);
int tempValue = nextRegister(moveType);
add(builder -> builder.addMoveResult(moveType, tempValue));
add(builder -> builder.addReturn(moveType, tempValue));
}
}
}
|