• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 
5 package com.android.tools.r8.ir.synthetic;
6 
7 import com.android.tools.r8.errors.Unimplemented;
8 import com.android.tools.r8.graph.DexMethod;
9 import com.android.tools.r8.graph.DexProto;
10 import com.android.tools.r8.graph.DexType;
11 import com.android.tools.r8.ir.code.Invoke;
12 import com.android.tools.r8.ir.code.MoveType;
13 import com.android.tools.r8.ir.conversion.IRBuilder;
14 import com.google.common.collect.Lists;
15 import java.util.ArrayList;
16 import java.util.List;
17 
18 // Source code representing simple forwarding method.
19 public final class ForwardMethodSourceCode extends SingleBlockSourceCode {
20 
21   private final DexType targetReceiver;
22   private final DexMethod target;
23   private final Invoke.Type invokeType;
24 
ForwardMethodSourceCode(DexType receiver, DexProto proto, DexType targetReceiver, DexMethod target, Invoke.Type invokeType)25   public ForwardMethodSourceCode(DexType receiver, DexProto proto,
26       DexType targetReceiver, DexMethod target, Invoke.Type invokeType) {
27     super(receiver, proto);
28     assert (targetReceiver == null) == (invokeType == Invoke.Type.STATIC);
29 
30     this.target = target;
31     this.targetReceiver = targetReceiver;
32     this.invokeType = invokeType;
33     assert checkSignatures();
34 
35     switch (invokeType) {
36       case STATIC:
37       case SUPER:
38       case INTERFACE:
39       case VIRTUAL:
40         break;
41       default:
42         throw new Unimplemented("Invoke type " + invokeType + " is not yet supported.");
43     }
44   }
45 
checkSignatures()46   private boolean checkSignatures() {
47     List<DexType> sourceParams = new ArrayList<>();
48     if (receiver != null) {
49       sourceParams.add(receiver);
50     }
51     sourceParams.addAll(Lists.newArrayList(proto.parameters.values));
52 
53     List<DexType> targetParams = new ArrayList<>();
54     if (targetReceiver != null) {
55       targetParams.add(targetReceiver);
56     }
57     targetParams.addAll(Lists.newArrayList(target.proto.parameters.values));
58 
59     assert sourceParams.size() == targetParams.size();
60     for (int i = 0; i < sourceParams.size(); i++) {
61       DexType source = sourceParams.get(i);
62       DexType target = targetParams.get(i);
63 
64       // We assume source is compatible with target if they both are classes.
65       // This check takes care of receiver widening conversion but does not
66       // many others, like conversion from an array to Object.
67       assert (source.isClassType() && target.isClassType()) || source == target;
68     }
69 
70     assert this.proto.returnType == target.proto.returnType;
71     return true;
72   }
73 
74   @Override
prepareInstructions()75   protected void prepareInstructions() {
76     // Prepare call arguments.
77     List<MoveType> argMoveTypes = new ArrayList<>();
78     List<Integer> argRegisters = new ArrayList<>();
79 
80     if (receiver != null) {
81       argMoveTypes.add(MoveType.OBJECT);
82       argRegisters.add(getReceiverRegister());
83     }
84 
85     DexType[] accessorParams = proto.parameters.values;
86     for (int i = 0; i < accessorParams.length; i++) {
87       argMoveTypes.add(MoveType.fromDexType(accessorParams[i]));
88       argRegisters.add(getParamRegister(i));
89     }
90 
91     // Method call to the target method.
92     add(builder -> builder.addInvoke(this.invokeType,
93         this.target, this.target.proto, argMoveTypes, argRegisters));
94 
95     // Does the method return value?
96     if (proto.returnType.isVoidType()) {
97       add(IRBuilder::addReturn);
98     } else {
99       MoveType moveType = MoveType.fromDexType(proto.returnType);
100       int tempValue = nextRegister(moveType);
101       add(builder -> builder.addMoveResult(moveType, tempValue));
102       add(builder -> builder.addReturn(moveType, tempValue));
103     }
104   }
105 }
106