blob: 750003fdc12b735f23805f82a7c2c5b8d1a09efb [file] [log] [blame]
// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Load;
import com.android.tools.r8.ir.code.MoveType;
import com.android.tools.r8.ir.code.Pop;
import com.android.tools.r8.ir.code.StackValue;
import com.android.tools.r8.ir.code.Store;
import com.android.tools.r8.ir.code.Value;
import java.util.ArrayList;
import java.util.List;
public class CfBuilder {
public enum LocalType {
REFERENCE,
INTEGER,
FLOAT,
LONG,
DOUBLE;
public static LocalType fromDexType(DexType type) {
switch (type.toShorty()) {
case 'Z':
case 'B':
case 'C':
case 'S':
case 'I':
return INTEGER;
case 'F':
return FLOAT;
case 'J':
return LONG;
case 'D':
return DOUBLE;
case 'L':
return REFERENCE;
default:
throw new Unreachable("Unexpected type " + type);
}
}
}
private final DexEncodedMethod method;
private final IRCode code;
private List<CfInstruction> instructions;
public static class StackHelper {
public final DexMethod method;
public StackHelper(DexMethod method) {
this.method = method;
}
public void loadInValues(
Instruction instruction,
List<Value> values,
List<LocalType> types,
InstructionListIterator it) {
assert values.size() == types.size();
it.previous();
for (int i = 0; i < values.size(); i++) {
Value value = values.get(i);
LocalType type = types.get(i);
StackValue stackValue = new StackValue(value.outType());
instruction.replaceValue(value, stackValue);
add(new Load(type, stackValue, value), instruction, it);
}
it.next();
}
public void storeOutValue(Instruction instruction, LocalType type, InstructionListIterator it) {
StackValue newOutValue = new StackValue(instruction.outType());
Value oldOutValue = instruction.swapOutValue(newOutValue);
add(new Store(type, oldOutValue, newOutValue), instruction, it);
}
public void popOutValue(Instruction instruction, MoveType type, InstructionListIterator it) {
StackValue newOutValue = new StackValue(type);
instruction.swapOutValue(newOutValue);
add(new Pop(newOutValue), instruction, it);
}
private static void add(
Instruction newInstruction, Instruction existingInstruction, InstructionListIterator it) {
newInstruction.setBlock(existingInstruction.getBlock());
newInstruction.setPosition(existingInstruction.getPosition());
it.add(newInstruction);
}
}
public CfBuilder(DexEncodedMethod method, IRCode code) {
this.method = method;
this.code = code;
}
public Code build() {
try {
loadStoreInsertion();
// TODO(zerny): Optimize load/store patterns.
// TODO(zerny): Compute locals/register allocation.
// TODO(zerny): Compute debug info.
return buildCfCode();
} catch (Unimplemented e) {
System.out.println("Incomplete CF construction: " + e.getMessage());
return method.getCode().asJarCode();
}
}
private void loadStoreInsertion() {
StackHelper stack = new StackHelper(method.method);
for (BasicBlock block : code.blocks) {
InstructionListIterator it = block.listIterator();
while (it.hasNext()) {
Instruction current = it.next();
current.insertLoadAndStores(it, stack);
}
}
}
private CfCode buildCfCode() {
instructions = new ArrayList<>();
InstructionIterator it = code.instructionIterator();
while (it.hasNext()) {
it.next().buildCf(this);
}
return new CfCode(instructions);
}
// Callbacks
public void add(CfInstruction instruction) {
instructions.add(instruction);
}
public void addArgument(Argument argument) {
// Nothing so far.
}
}