• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016, 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.MoveResult;
7 import com.android.tools.r8.code.MoveResultObject;
8 import com.android.tools.r8.code.MoveResultWide;
9 import com.android.tools.r8.dex.Constants;
10 import com.android.tools.r8.errors.Unreachable;
11 import com.android.tools.r8.graph.AppInfoWithSubtyping;
12 import com.android.tools.r8.graph.DexEncodedMethod;
13 import com.android.tools.r8.graph.DexItem;
14 import com.android.tools.r8.graph.DexMethod;
15 import com.android.tools.r8.graph.DexProto;
16 import com.android.tools.r8.graph.DexType;
17 import com.android.tools.r8.ir.conversion.DexBuilder;
18 import java.util.List;
19 
20 public abstract class Invoke extends Instruction {
21 
22   public enum Type {
23     DIRECT,
24     INTERFACE,
25     STATIC,
26     SUPER,
27     VIRTUAL,
28     NEW_ARRAY,
29     CUSTOM,
30     POLYMORPHIC
31   }
32 
Invoke(Value result, List<Value> arguments)33   public Invoke(Value result, List<Value> arguments) {
34     super(result, arguments);
35   }
36 
create( Type type, DexItem target, DexProto proto, Value result, List<Value> arguments)37   public static Invoke create(
38       Type type, DexItem target, DexProto proto, Value result, List<Value> arguments) {
39     switch (type) {
40       case DIRECT:
41         return new InvokeDirect((DexMethod) target, result, arguments);
42       case INTERFACE:
43         return new InvokeInterface((DexMethod) target, result, arguments);
44       case STATIC:
45         return new InvokeStatic((DexMethod) target, result, arguments);
46       case SUPER:
47         return new InvokeSuper((DexMethod) target, result, arguments);
48       case VIRTUAL:
49         return new InvokeVirtual((DexMethod) target, result, arguments);
50       case NEW_ARRAY:
51         return new InvokeNewArray((DexType) target, result, arguments);
52       case CUSTOM:
53         throw new Unreachable("Use InvokeCustom constructor instead");
54       case POLYMORPHIC:
55         return new InvokePolymorphic((DexMethod) target, proto, result, arguments);
56     }
57     throw new Unreachable("Unknown invoke type: " + type);
58   }
59 
createFromTemplate( Invoke template, Value outValue, List<Value> inValues)60   public static Instruction createFromTemplate(
61       Invoke template, Value outValue, List<Value> inValues) {
62     if (template.isInvokeMethod()) {
63       return create(template.getType(),
64           template.asInvokeMethod().getInvokedMethod(),
65           template.isInvokePolymorphic() ? template.asInvokePolymorphic().getProto() : null,
66           outValue,
67           inValues);
68     }
69 
70     if (template.isInvokeNewArray()) {
71       return new InvokeNewArray(template.asInvokeNewArray().getArrayType(), outValue, inValues);
72     }
73 
74     assert template.isInvokeCustom();
75     InvokeCustom custom = template.asInvokeCustom();
76     return new InvokeCustom(custom.getCallSite(), outValue, inValues);
77   }
78 
getType()79   abstract public Type getType();
80 
arguments()81   public List<Value> arguments() {
82     return inValues;
83   }
84 
requiredArgumentRegisters()85   public int requiredArgumentRegisters() {
86     int registers = 0;
87     for (Value inValue : inValues) {
88       registers += inValue.requiredRegisters();
89     }
90     return registers;
91   }
92 
argumentRegisterValue(int i, DexBuilder builder)93   protected int argumentRegisterValue(int i, DexBuilder builder) {
94     assert needsRangedInvoke(builder);
95     if (i < arguments().size()) {
96       // If argument values flow into ranged invokes, all the ranged invoke arguments
97       // are arguments to this method in order. Therefore, we use the incoming registers
98       // for the ranged invoke arguments. We know that arguments are always available there.
99       // If argument reuse is allowed there is no splitting and if argument reuse is disallowed
100       // the argument registers are never overwritten.
101       return builder.argumentOrAllocateRegister(arguments().get(i), getNumber());
102     }
103     return 0;
104   }
105 
fillArgumentRegisters(DexBuilder builder, int[] registers)106   protected int fillArgumentRegisters(DexBuilder builder, int[] registers) {
107     int i = 0;
108     for (Value value : arguments()) {
109       int register = builder.allocatedRegister(value, getNumber());
110       for (int j = 0; j < value.requiredRegisters(); j++) {
111         assert i < 5;
112         registers[i++] = register++;
113       }
114     }
115     return i;
116   }
117 
118   protected boolean hasHighArgumentRegister(DexBuilder builder) {
119     for (Value value : arguments()) {
120       if (builder.argumentValueUsesHighRegister(value, getNumber())) {
121         return true;
122       }
123     }
124     return false;
125   }
126 
127   protected boolean argumentsConsecutive(DexBuilder builder) {
128     Value value = arguments().get(0);
129     int next = builder.argumentOrAllocateRegister(value, getNumber()) + value.requiredRegisters();
130     for (int i = 1; i < arguments().size(); i++) {
131       value = arguments().get(i);
132       assert next == builder.argumentOrAllocateRegister(value, getNumber());
133       next += value.requiredRegisters();
134     }
135     return true;
136   }
137 
138   protected void addInvokeAndMoveResult(com.android.tools.r8.code.Instruction instruction, DexBuilder builder) {
139     if (outValue != null && outValue.needsRegister()) {
140       int register = builder.allocatedRegister(outValue, getNumber());
141       com.android.tools.r8.code.Instruction moveResult;
142       switch (outType()) {
143         case SINGLE:
144           moveResult = new MoveResult(register);
145           break;
146         case WIDE:
147           moveResult = new MoveResultWide(register);
148           break;
149         case OBJECT:
150           moveResult = new MoveResultObject(register);
151           break;
152         default:
153           throw new Unreachable("Unexpected result type " + outType());
154       }
155       builder.add(this, new com.android.tools.r8.code.Instruction[]{instruction, moveResult});
156     } else {
157       builder.add(this, instruction);
158     }
159   }
160 
161   @Override
162   public boolean instructionTypeCanThrow() {
163     return true;
164   }
165 
166   @Override
167   public int maxInValueRegister() {
168     if (requiredArgumentRegisters() > 5) {
169       return Constants.U16BIT_MAX;
170     }
171     if (argumentsAreConsecutiveInputArguments()) {
172       return Constants.U16BIT_MAX;
173     }
174     return Constants.U4BIT_MAX;
175   }
176 
177   private boolean argumentsAreConsecutiveInputArguments() {
178     if (arguments().size() == 0) {
179       return false;
180     }
181     Value current = arguments().get(0);
182     if (!current.isArgument()) {
183       return false;
184     }
185     for (int i = 1; i < arguments().size(); i++) {
186       Value next = arguments().get(i);
187       if (current.getNextConsecutive() != next) {
188         return false;
189       }
190       current = next;
191     }
192     return true;
193   }
194 
195   private boolean argumentsAreConsecutiveInputArgumentsWithHighRegisters(
196       DexBuilder builder) {
197     if (!argumentsAreConsecutiveInputArguments()) {
198       return false;
199     }
200     Value lastArgument = arguments().get(arguments().size() - 1);
201     return builder.argumentOrAllocateRegister(lastArgument, getNumber()) > Constants.U4BIT_MAX;
202   }
203 
204   protected boolean needsRangedInvoke(DexBuilder builder) {
205     return requiredArgumentRegisters() > 5
206         || hasHighArgumentRegister(builder)
207         || argumentsAreConsecutiveInputArgumentsWithHighRegisters(builder);
208   }
209 
210   @Override
maxOutValueRegister()211   public int maxOutValueRegister() {
212     return Constants.U8BIT_MAX;
213   }
214 
215   abstract protected String getTypeString();
216 
217   @Override
getInstructionName()218   public String getInstructionName() {
219     return "Invoke-" + getTypeString();
220   }
221 
222   // This method is used for inlining.
223   // It returns the target method iff this invoke has only one target.
224   abstract public DexEncodedMethod computeSingleTarget(AppInfoWithSubtyping appInfo);
225 
226   @Override
isInvoke()227   public boolean isInvoke() {
228     return true;
229   }
230 
231   @Override
asInvoke()232   public Invoke asInvoke() {
233     return this;
234   }
235 }
236