blob: b182afba11fe4d35a56fe90652889dbfef80aeed [file] [log] [blame]
// Copyright (c) 2020, 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.horizontalclassmerging;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
import com.android.tools.r8.utils.IntBox;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Generate code of the form: <code>
* MyClass(int constructorId, [args]) {
* switch (constructorId) {
* case 0:
* this.Constructor$A([args]);
* return;
* case 1:
* this.Constructor$B([args]);
* return;
* ...
* default:
* throw null;
* }
* }
* </code>
*/
public class ConstructorEntryPoint extends SyntheticSourceCode {
private final Collection<DexMethod> typeConstructors;
public ConstructorEntryPoint(
Collection<DexMethod> typeConstructors, DexMethod method, Position callerPosition) {
super(method.holder, method, callerPosition);
this.typeConstructors = typeConstructors;
}
@Override
protected void prepareInstructions() {
int typeConstructorCount = typeConstructors.size();
int idRegister = getParamRegister(0);
int[] keys = new int[typeConstructorCount];
int[] offsets = new int[typeConstructorCount];
IntBox fallthrough = new IntBox();
int switchIndex = lastInstructionIndex();
add(
builder -> builder.addSwitch(idRegister, keys, fallthrough.get(), offsets),
builder -> endsSwitch(builder, switchIndex, fallthrough.get(), offsets));
fallthrough.set(nextInstructionIndex());
int nullRegister = nextRegister(ValueType.OBJECT);
add(builder -> builder.addNullConst(nullRegister));
add(builder -> builder.addThrow(nullRegister), endsBlock);
int index = 0;
for (DexMethod typeConstructor : typeConstructors) {
keys[index] = index;
offsets[index] = nextInstructionIndex();
add(
builder -> {
List<Value> arguments = new ArrayList<>(typeConstructor.getArity());
arguments.add(builder.getReceiverValue());
int paramIndex = 0;
for (Value argument : builder.getArgumentValues()) {
if (paramIndex++ >= typeConstructor.getArity()) {
break;
}
arguments.add(argument);
}
builder.addInvoke(
Type.DIRECT, typeConstructor, typeConstructor.proto, arguments, false);
});
add(IRBuilder::addReturn, endsBlock);
index++;
}
}
}