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