aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/android/tools/r8/ir/synthetic
diff options
context:
space:
mode:
authorStephan Herhut <herhut@google.com>2017-05-30 14:33:11 +0200
committerStephan Herhut <herhut@google.com>2017-05-30 14:33:11 +0200
commit080ec2d61f7b055a55802c072e77e99514499b8f (patch)
tree28386639b10843613c493ff7a5501371539f4c04 /src/main/java/com/android/tools/r8/ir/synthetic
parent35b1cb677b6db60e48c4aec18b5649082152afd9 (diff)
downloadr8-080ec2d61f7b055a55802c072e77e99514499b8f.tar.gz
Reland "Insert bridge methods in member rebinding if target is otherwise not visible."
Bug: Change-Id: Icdf351384330ca4781d1dfbd510f1be68c0874f4
Diffstat (limited to 'src/main/java/com/android/tools/r8/ir/synthetic')
-rw-r--r--src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java105
-rw-r--r--src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java213
-rw-r--r--src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java67
3 files changed, 385 insertions, 0 deletions
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
new file mode 100644
index 000000000..bcc9462be
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/ForwardMethodSourceCode.java
@@ -0,0 +1,105 @@
+// 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.synthetic;
+
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.List;
+
+// Source code representing simple forwarding method.
+public final class ForwardMethodSourceCode extends SingleBlockSourceCode {
+
+ private final DexType targetReceiver;
+ private final DexMethod target;
+ private final Invoke.Type invokeType;
+
+ public ForwardMethodSourceCode(DexType receiver, DexProto proto,
+ DexType targetReceiver, DexMethod target, Invoke.Type invokeType) {
+ super(receiver, proto);
+ assert (targetReceiver == null) == (invokeType == Invoke.Type.STATIC);
+
+ this.target = target;
+ this.targetReceiver = targetReceiver;
+ this.invokeType = invokeType;
+ assert checkSignatures();
+
+ switch (invokeType) {
+ case STATIC:
+ case SUPER:
+ case INTERFACE:
+ case VIRTUAL:
+ break;
+ default:
+ throw new Unimplemented("Invoke type " + invokeType + " is not yet supported.");
+ }
+ }
+
+ private boolean checkSignatures() {
+ List<DexType> sourceParams = new ArrayList<>();
+ if (receiver != null) {
+ sourceParams.add(receiver);
+ }
+ sourceParams.addAll(Lists.newArrayList(proto.parameters.values));
+
+ List<DexType> targetParams = new ArrayList<>();
+ if (targetReceiver != null) {
+ targetParams.add(targetReceiver);
+ }
+ targetParams.addAll(Lists.newArrayList(target.proto.parameters.values));
+
+ assert sourceParams.size() == targetParams.size();
+ for (int i = 0; i < sourceParams.size(); i++) {
+ DexType source = sourceParams.get(i);
+ DexType target = targetParams.get(i);
+
+ // We assume source is compatible with target if they both are classes.
+ // This check takes care of receiver widening conversion but does not
+ // many others, like conversion from an array to Object.
+ assert (source.isClassType() && target.isClassType()) || source == target;
+ }
+
+ assert this.proto.returnType == target.proto.returnType;
+ return true;
+ }
+
+ @Override
+ protected void prepareInstructions() {
+ // Prepare call arguments.
+ List<MoveType> argMoveTypes = new ArrayList<>();
+ List<Integer> argRegisters = new ArrayList<>();
+
+ if (receiver != null) {
+ argMoveTypes.add(MoveType.OBJECT);
+ argRegisters.add(getReceiverRegister());
+ }
+
+ DexType[] accessorParams = proto.parameters.values;
+ for (int i = 0; i < accessorParams.length; i++) {
+ argMoveTypes.add(MoveType.fromDexType(accessorParams[i]));
+ argRegisters.add(getParamRegister(i));
+ }
+
+ // Method call to the target method.
+ add(builder -> builder.addInvoke(this.invokeType,
+ this.target, this.target.proto, argMoveTypes, argRegisters));
+
+ // Does the method return value?
+ if (proto.returnType.isVoidType()) {
+ add(IRBuilder::addReturn);
+ } else {
+ MoveType moveType = MoveType.fromDexType(proto.returnType);
+ int tempValue = nextRegister(moveType);
+ add(builder -> builder.addMoveResult(moveType, tempValue));
+ add(builder -> builder.addReturn(moveType, tempValue));
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
new file mode 100644
index 000000000..8c97f8ff1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SingleBlockSourceCode.java
@@ -0,0 +1,213 @@
+// 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.synthetic;
+
+import static com.android.tools.r8.ir.code.BasicBlock.ThrowingInfo.NO_THROW;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.Argument;
+import com.android.tools.r8.ir.code.CatchHandlers;
+import com.android.tools.r8.ir.code.MoveType;
+import com.android.tools.r8.ir.code.Switch;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.SourceCode;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+public abstract class SingleBlockSourceCode implements SourceCode {
+
+ protected final DexType receiver;
+ protected final DexProto proto;
+
+ // The next free register, note that we always
+ // assign each value a new (next available) register.
+ private int nextRegister = 0;
+
+ // Registers for receiver and parameters
+ private final int receiverRegister;
+ private int[] paramRegisters;
+ // Values representing receiver and parameters will be filled in
+ // buildPrelude() and should only be accessed via appropriate methods
+ private Value receiverValue;
+ private Value[] paramValues;
+
+ // Instruction constructors
+ private List<Consumer<IRBuilder>> constructors = new ArrayList<>();
+
+ protected SingleBlockSourceCode(DexType receiver, DexProto proto) {
+ assert proto != null;
+ this.receiver = receiver;
+ this.proto = proto;
+
+ // Initialize register values for receiver and arguments
+ this.receiverRegister = receiver != null ? nextRegister(MoveType.OBJECT) : -1;
+
+ DexType[] params = proto.parameters.values;
+ int paramCount = params.length;
+ this.paramRegisters = new int[paramCount];
+ this.paramValues = new Value[paramCount];
+ for (int i = 0; i < paramCount; i++) {
+ this.paramRegisters[i] = nextRegister(MoveType.fromDexType(params[i]));
+ }
+ }
+
+ protected final void add(Consumer<IRBuilder> constructor) {
+ constructors.add(constructor);
+ }
+
+ protected final int nextRegister(MoveType type) {
+ int value = nextRegister;
+ nextRegister += type == MoveType.WIDE ? 2 : 1;
+ return value;
+ }
+
+ protected final Value getReceiverValue() {
+ assert receiver != null;
+ assert receiverValue != null;
+ return receiverValue;
+ }
+
+ protected final int getReceiverRegister() {
+ assert receiver != null;
+ assert receiverRegister >= 0;
+ return receiverRegister;
+ }
+
+ protected final Value getParamValue(int paramIndex) {
+ assert paramIndex >= 0;
+ assert paramIndex < paramValues.length;
+ return paramValues[paramIndex];
+ }
+
+ protected final int getParamCount() {
+ return paramValues.length;
+ }
+
+ protected final int getParamRegister(int paramIndex) {
+ assert paramIndex >= 0;
+ assert paramIndex < paramRegisters.length;
+ return paramRegisters[paramIndex];
+ }
+
+ protected abstract void prepareInstructions();
+
+ @Override
+ public final boolean needsPrelude() {
+ return receiver != null || paramRegisters.length > 0;
+ }
+
+ @Override
+ public final int instructionCount() {
+ return constructors.size();
+ }
+
+ @Override
+ public final int instructionIndex(int instructionOffset) {
+ return instructionOffset;
+ }
+
+ @Override
+ public final int instructionOffset(int instructionIndex) {
+ return instructionIndex;
+ }
+
+ @Override
+ public DebugLocalInfo getCurrentLocal(int register) {
+ return null;
+ }
+
+ @Override
+ public final boolean traceInstruction(int instructionIndex, IRBuilder builder) {
+ return instructionIndex == constructors.size() - 1;
+ }
+
+ @Override
+ public final void closedCurrentBlockWithFallthrough(int fallthroughInstructionIndex) {
+ }
+
+ @Override
+ public final void closedCurrentBlock() {
+ }
+
+ @Override
+ public final void setUp() {
+ assert constructors.isEmpty();
+ prepareInstructions();
+ assert !constructors.isEmpty();
+ }
+
+ @Override
+ public final void clear() {
+ constructors = null;
+ paramRegisters = null;
+ paramValues = null;
+ receiverValue = null;
+ }
+
+ @Override
+ public final void buildPrelude(IRBuilder builder) {
+ if (receiver != null) {
+ receiverValue = builder.writeRegister(receiverRegister, MoveType.OBJECT, NO_THROW);
+ builder.add(new Argument(receiverValue));
+ }
+
+ // Fill in the Argument instructions in the argument block.
+ DexType[] parameters = proto.parameters.values;
+ for (int i = 0; i < parameters.length; i++) {
+ MoveType moveType = MoveType.fromDexType(parameters[i]);
+ Value paramValue = builder.writeRegister(paramRegisters[i], moveType, NO_THROW);
+ paramValues[i] = paramValue;
+ builder.add(new Argument(paramValue));
+ }
+ }
+
+ @Override
+ public final void buildPostlude(IRBuilder builder) {
+ // Intentionally left empty.
+ }
+
+ @Override
+ public final void buildInstruction(IRBuilder builder, int instructionIndex) {
+ constructors.get(instructionIndex).accept(builder);
+ }
+
+ @Override
+ public final void resolveAndBuildSwitch(
+ Switch.Type type, int value, int fallthroughOffset,
+ int payloadOffset, IRBuilder builder) {
+ throw new Unreachable("Unexpected call to resolveAndBuildSwitch");
+ }
+
+ @Override
+ public final void resolveAndBuildNewArrayFilledData(
+ int arrayRef, int payloadOffset, IRBuilder builder) {
+ throw new Unreachable("Unexpected call to resolveAndBuildNewArrayFilledData");
+ }
+
+ @Override
+ public final CatchHandlers<Integer> getCurrentCatchHandlers() {
+ return null;
+ }
+
+ @Override
+ public final boolean verifyCurrentInstructionCanThrow() {
+ return true;
+ }
+
+ @Override
+ public boolean verifyLocalInScope(DebugLocalInfo local) {
+ return true;
+ }
+
+ @Override
+ public final boolean verifyRegister(int register) {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
new file mode 100644
index 000000000..7716663f7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/SynthesizedCode.java
@@ -0,0 +1,67 @@
+// 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.synthetic;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.SourceCode;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.InternalOptions;
+import java.util.function.Consumer;
+
+public final class SynthesizedCode extends Code {
+
+ private final SourceCode sourceCode;
+ private final Consumer<UseRegistry> registryCallback;
+
+ public SynthesizedCode(SourceCode sourceCode) {
+ this.sourceCode = sourceCode;
+ this.registryCallback = SynthesizedCode::registerReachableDefinitionsDefault;
+ }
+
+ public SynthesizedCode(SourceCode sourceCode, Consumer<UseRegistry> callback) {
+ this.sourceCode = sourceCode;
+ this.registryCallback = callback;
+ }
+
+ @Override
+ public final IRCode buildIR(DexEncodedMethod encodedMethod, InternalOptions options) {
+ return new IRBuilder(encodedMethod, sourceCode, options).build();
+ }
+
+ @Override
+ public final String toString() {
+ return toString(null);
+ }
+
+ private static void registerReachableDefinitionsDefault(UseRegistry registry) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public void registerReachableDefinitions(UseRegistry registry) {
+ registryCallback.accept(registry);
+ }
+
+ @Override
+ protected final int computeHashCode() {
+ return sourceCode.hashCode();
+ }
+
+ @Override
+ protected final boolean computeEquals(Object other) {
+ return other instanceof SynthesizedCode &&
+ this.sourceCode.equals(((SynthesizedCode) other).sourceCode);
+ }
+
+ @Override
+ public final String toString(ClassNameMapper naming) {
+ return "SynthesizedCode: " + sourceCode.toString();
+ }
+}