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 static com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo.NO_THROW; 8 9 import com.android.tools.r8.errors.Unreachable; 10 import com.android.tools.r8.graph.DebugLocalInfo; 11 import com.android.tools.r8.graph.DexProto; 12 import com.android.tools.r8.graph.DexType; 13 import com.android.tools.r8.ir.code.Argument; 14 import com.android.tools.r8.ir.code.CatchHandlers; 15 import com.android.tools.r8.ir.code.MoveType; 16 import com.android.tools.r8.ir.code.Value; 17 import com.android.tools.r8.ir.conversion.IRBuilder; 18 import com.android.tools.r8.ir.conversion.SourceCode; 19 import java.util.ArrayList; 20 import java.util.List; 21 import java.util.function.Consumer; 22 23 public abstract class SingleBlockSourceCode implements SourceCode { 24 25 protected final DexType receiver; 26 protected final DexProto proto; 27 28 // The next free register, note that we always 29 // assign each value a new (next available) register. 30 private int nextRegister = 0; 31 32 // Registers for receiver and parameters 33 private final int receiverRegister; 34 private int[] paramRegisters; 35 // Values representing receiver and parameters will be filled in 36 // buildPrelude() and should only be accessed via appropriate methods 37 private Value receiverValue; 38 private Value[] paramValues; 39 40 // Instruction constructors 41 private List<Consumer<IRBuilder>> constructors = new ArrayList<>(); 42 43 protected SingleBlockSourceCode(DexType receiver, DexProto proto) { 44 assert proto != null; 45 this.receiver = receiver; 46 this.proto = proto; 47 48 // Initialize register values for receiver and arguments 49 this.receiverRegister = receiver != null ? nextRegister(MoveType.OBJECT) : -1; 50 51 DexType[] params = proto.parameters.values; 52 int paramCount = params.length; 53 this.paramRegisters = new int[paramCount]; 54 this.paramValues = new Value[paramCount]; 55 for (int i = 0; i < paramCount; i++) { 56 this.paramRegisters[i] = nextRegister(MoveType.fromDexType(params[i])); 57 } 58 } 59 60 protected final void add(Consumer<IRBuilder> constructor) { 61 constructors.add(constructor); 62 } 63 64 protected final int nextRegister(MoveType type) { 65 int value = nextRegister; 66 nextRegister += type == MoveType.WIDE ? 2 : 1; 67 return value; 68 } 69 70 protected final Value getReceiverValue() { 71 assert receiver != null; 72 assert receiverValue != null; 73 return receiverValue; 74 } 75 76 protected final int getReceiverRegister() { 77 assert receiver != null; 78 assert receiverRegister >= 0; 79 return receiverRegister; 80 } 81 82 protected final Value getParamValue(int paramIndex) { 83 assert paramIndex >= 0; 84 assert paramIndex < paramValues.length; 85 return paramValues[paramIndex]; 86 } 87 88 protected final int getParamCount() { 89 return paramValues.length; 90 } 91 92 protected final int getParamRegister(int paramIndex) { 93 assert paramIndex >= 0; 94 assert paramIndex < paramRegisters.length; 95 return paramRegisters[paramIndex]; 96 } 97 98 protected abstract void prepareInstructions(); 99 100 @Override 101 public final boolean needsPrelude() { 102 return receiver != null || paramRegisters.length > 0; 103 } 104 105 @Override 106 public final int instructionCount() { 107 return constructors.size(); 108 } 109 110 @Override 111 public final int instructionIndex(int instructionOffset) { 112 return instructionOffset; 113 } 114 115 @Override 116 public final int instructionOffset(int instructionIndex) { 117 return instructionIndex; 118 } 119 120 @Override 121 public DebugLocalInfo getCurrentLocal(int register) { 122 return null; 123 } 124 125 @Override 126 public final int traceInstruction(int instructionIndex, IRBuilder builder) { 127 return (instructionIndex == constructors.size() - 1) ? instructionIndex : -1; 128 } 129 130 @Override 131 public final void closedCurrentBlockWithFallthrough(int fallthroughInstructionIndex) { 132 } 133 134 @Override 135 public final void closedCurrentBlock() { 136 } 137 138 @Override 139 public final void setUp() { 140 assert constructors.isEmpty(); 141 prepareInstructions(); 142 assert !constructors.isEmpty(); 143 } 144 145 @Override 146 public final void clear() { 147 constructors = null; 148 paramRegisters = null; 149 paramValues = null; 150 receiverValue = null; 151 } 152 153 @Override 154 public final void buildPrelude(IRBuilder builder) { 155 if (receiver != null) { 156 receiverValue = builder.writeRegister(receiverRegister, MoveType.OBJECT, NO_THROW); 157 builder.add(new Argument(receiverValue)); 158 } 159 160 // Fill in the Argument instructions in the argument block. 161 DexType[] parameters = proto.parameters.values; 162 for (int i = 0; i < parameters.length; i++) { 163 MoveType moveType = MoveType.fromDexType(parameters[i]); 164 Value paramValue = builder.writeRegister(paramRegisters[i], moveType, NO_THROW); 165 paramValues[i] = paramValue; 166 builder.add(new Argument(paramValue)); 167 } 168 } 169 170 @Override 171 public final void buildPostlude(IRBuilder builder) { 172 // Intentionally left empty. 173 } 174 175 @Override 176 public final void buildInstruction(IRBuilder builder, int instructionIndex) { 177 constructors.get(instructionIndex).accept(builder); 178 } 179 180 @Override 181 public final void resolveAndBuildSwitch( 182 int value, int fallthroughOffset, int payloadOffset, IRBuilder builder) { 183 throw new Unreachable("Unexpected call to resolveAndBuildSwitch"); 184 } 185 186 @Override 187 public final void resolveAndBuildNewArrayFilledData( 188 int arrayRef, int payloadOffset, IRBuilder builder) { 189 throw new Unreachable("Unexpected call to resolveAndBuildNewArrayFilledData"); 190 } 191 192 @Override 193 public final CatchHandlers<Integer> getCurrentCatchHandlers() { 194 return null; 195 } 196 197 @Override 198 public final boolean verifyCurrentInstructionCanThrow() { 199 return true; 200 } 201 202 @Override 203 public boolean verifyLocalInScope(DebugLocalInfo local) { 204 return true; 205 } 206 207 @Override 208 public final boolean verifyRegister(int register) { 209 return true; 210 } 211 } 212