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 package com.android.tools.r8.ir.code; 5 6 import com.android.tools.r8.code.InvokeDirectRange; 7 import com.android.tools.r8.dex.Constants; 8 import com.android.tools.r8.graph.AppInfoWithSubtyping; 9 import com.android.tools.r8.graph.DexEncodedMethod; 10 import com.android.tools.r8.graph.DexMethod; 11 import com.android.tools.r8.ir.conversion.DexBuilder; 12 import com.android.tools.r8.ir.optimize.Inliner.InlineAction; 13 import com.android.tools.r8.ir.optimize.InliningOracle; 14 import java.util.List; 15 16 public class InvokeDirect extends InvokeMethodWithReceiver { 17 InvokeDirect(DexMethod target, Value result, List<Value> arguments)18 public InvokeDirect(DexMethod target, Value result, List<Value> arguments) { 19 super(target, result, arguments); 20 } 21 22 @Override getType()23 public Type getType() { 24 return Type.DIRECT; 25 } 26 27 @Override getTypeString()28 protected String getTypeString() { 29 return "Direct"; 30 } 31 32 @Override computeSingleTarget(AppInfoWithSubtyping appInfo)33 public DexEncodedMethod computeSingleTarget(AppInfoWithSubtyping appInfo) { 34 return appInfo.lookupDirectTarget(getInvokedMethod()); 35 } 36 37 @Override buildDex(DexBuilder builder)38 public void buildDex(DexBuilder builder) { 39 com.android.tools.r8.code.Instruction instruction; 40 int argumentRegisters = requiredArgumentRegisters(); 41 builder.requestOutgoingRegisters(argumentRegisters); 42 if (needsRangedInvoke(builder)) { 43 assert argumentsConsecutive(builder); 44 int firstRegister = argumentRegisterValue(0, builder); 45 instruction = new InvokeDirectRange(firstRegister, argumentRegisters, getInvokedMethod()); 46 } else { 47 int[] individualArgumentRegisters = new int[5]; 48 int argumentRegistersCount = fillArgumentRegisters(builder, individualArgumentRegisters); 49 instruction = new com.android.tools.r8.code.InvokeDirect( 50 argumentRegistersCount, 51 getInvokedMethod(), 52 individualArgumentRegisters[0], // C 53 individualArgumentRegisters[1], // D 54 individualArgumentRegisters[2], // E 55 individualArgumentRegisters[3], // F 56 individualArgumentRegisters[4]); // G 57 } 58 addInvokeAndMoveResult(instruction, builder); 59 } 60 61 /** 62 * Two invokes of a constructor are only allowed to be considered equal if the object 63 * they are initializing is the same. Art rejects code that has objects created by 64 * different new-instance instructions flow to one constructor invoke. 65 */ sameConstructorReceiverValue(Invoke other)66 public boolean sameConstructorReceiverValue(Invoke other) { 67 if (!getInvokedMethod().name.toString().equals(Constants.INSTANCE_INITIALIZER_NAME)) { 68 return true; 69 } 70 return inValues.get(0) == other.inValues.get(0); 71 } 72 73 @Override identicalNonValueParts(Instruction other)74 public boolean identicalNonValueParts(Instruction other) { 75 if (!other.isInvokeDirect()) { 76 return false; 77 } 78 return super.identicalNonValueParts(other); 79 } 80 81 @Override isInvokeDirect()82 public boolean isInvokeDirect() { 83 return true; 84 } 85 86 @Override asInvokeDirect()87 public InvokeDirect asInvokeDirect() { 88 return this; 89 } 90 91 @Override computeInlining(InliningOracle decider)92 public InlineAction computeInlining(InliningOracle decider) { 93 return decider.computeForInvokeDirect(this); 94 } 95 } 96