Home | History | Annotate | Download | only in synthetic
      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