blob: 4eda679c5bc63c0505572881c9a6e6a1b00efcf9 [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.graph;
import com.android.tools.r8.utils.PredicateUtils;
import com.android.tools.r8.utils.TraversalContinuation;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
public class MethodArrayBacking extends MethodCollectionBacking {
private DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY;
private DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY;
private boolean verifyNoDuplicateMethods() {
Set<DexMethod> unique = Sets.newIdentityHashSet();
forEachMethod(
method -> {
boolean changed = unique.add(method.method);
assert changed : "Duplicate method `" + method.method.toSourceString() + "`";
});
return true;
}
@Override
boolean verify() {
assert verifyNoDuplicateMethods();
return true;
}
@Override
int size() {
return directMethods.length + virtualMethods.length;
}
@Override
TraversalContinuation traverse(Function<DexEncodedMethod, TraversalContinuation> fn) {
for (DexEncodedMethod method : directMethods) {
TraversalContinuation stepResult = fn.apply(method);
if (stepResult.shouldBreak()) {
return stepResult;
}
}
for (DexEncodedMethod method : virtualMethods) {
TraversalContinuation stepResult = fn.apply(method);
if (stepResult.shouldBreak()) {
return stepResult;
}
}
return TraversalContinuation.CONTINUE;
}
@Override
public Iterable<DexEncodedMethod> methods() {
return Iterables.concat(Arrays.asList(directMethods), Arrays.asList(virtualMethods));
}
@Override
List<DexEncodedMethod> directMethods() {
assert directMethods != null;
return Arrays.asList(directMethods);
}
@Override
void addDirectMethods(Collection<DexEncodedMethod> methods) {
DexEncodedMethod[] newMethods = new DexEncodedMethod[directMethods.length + methods.size()];
System.arraycopy(directMethods, 0, newMethods, 0, directMethods.length);
int i = directMethods.length;
for (DexEncodedMethod method : methods) {
newMethods[i] = method;
i++;
}
directMethods = newMethods;
assert verifyNoDuplicateMethods();
}
private void removeDirectMethod(int index) {
DexEncodedMethod[] newMethods = new DexEncodedMethod[directMethods.length - 1];
System.arraycopy(directMethods, 0, newMethods, 0, index);
System.arraycopy(directMethods, index + 1, newMethods, index, directMethods.length - index - 1);
directMethods = newMethods;
}
@Override
void removeDirectMethod(DexMethod method) {
int index = -1;
for (int i = 0; i < directMethods.length; i++) {
if (method.match(directMethods[i])) {
index = i;
break;
}
}
if (index >= 0) {
removeDirectMethod(index);
}
}
@Override
void setDirectMethods(DexEncodedMethod[] methods) {
directMethods = MoreObjects.firstNonNull(methods, DexEncodedMethod.EMPTY_ARRAY);
assert verifyNoDuplicateMethods();
}
@Override
List<DexEncodedMethod> virtualMethods() {
assert virtualMethods != null;
return Arrays.asList(virtualMethods);
}
@Override
void addVirtualMethods(Collection<DexEncodedMethod> methods) {
DexEncodedMethod[] newMethods = new DexEncodedMethod[virtualMethods.length + methods.size()];
System.arraycopy(virtualMethods, 0, newMethods, 0, virtualMethods.length);
int i = virtualMethods.length;
for (DexEncodedMethod method : methods) {
newMethods[i] = method;
i++;
}
virtualMethods = newMethods;
assert verifyNoDuplicateMethods();
}
@Override
void setVirtualMethods(DexEncodedMethod[] methods) {
virtualMethods = MoreObjects.firstNonNull(methods, DexEncodedMethod.EMPTY_ARRAY);
assert verifyNoDuplicateMethods();
}
@Override
void virtualizeMethods(Set<DexEncodedMethod> privateInstanceMethods) {
int vLen = virtualMethods.length;
int dLen = directMethods.length;
int mLen = privateInstanceMethods.size();
assert mLen <= dLen;
DexEncodedMethod[] newDirectMethods = new DexEncodedMethod[dLen - mLen];
int index = 0;
for (int i = 0; i < dLen; i++) {
DexEncodedMethod encodedMethod = directMethods[i];
if (!privateInstanceMethods.contains(encodedMethod)) {
newDirectMethods[index++] = encodedMethod;
}
}
assert index == dLen - mLen;
setDirectMethods(newDirectMethods);
DexEncodedMethod[] newVirtualMethods = new DexEncodedMethod[vLen + mLen];
System.arraycopy(virtualMethods, 0, newVirtualMethods, 0, vLen);
index = vLen;
for (DexEncodedMethod encodedMethod : privateInstanceMethods) {
newVirtualMethods[index++] = encodedMethod;
}
setVirtualMethods(newVirtualMethods);
}
@Override
DexEncodedMethod getDirectMethod(DexMethod method) {
for (DexEncodedMethod directMethod : directMethods) {
if (method.match(directMethod)) {
return directMethod;
}
}
return null;
}
@Override
DexEncodedMethod getDirectMethod(Predicate<DexEncodedMethod> predicate) {
return PredicateUtils.findFirst(directMethods, predicate);
}
@Override
DexEncodedMethod getVirtualMethod(DexMethod method) {
for (DexEncodedMethod virtualMethod : virtualMethods) {
if (method.match(virtualMethod)) {
return virtualMethod;
}
}
return null;
}
@Override
DexEncodedMethod getVirtualMethod(Predicate<DexEncodedMethod> predicate) {
return PredicateUtils.findFirst(virtualMethods, predicate);
}
@Override
DexEncodedMethod getMethod(DexMethod method) {
DexEncodedMethod result = getDirectMethod(method);
return result == null ? getVirtualMethod(method) : result;
}
@Override
void addMethod(DexEncodedMethod method) {
if (belongsToDirectPool(method)) {
addDirectMethod(method);
} else {
addVirtualMethod(method);
}
}
@Override
void addVirtualMethod(DexEncodedMethod virtualMethod) {
assert belongsToVirtualPool(virtualMethod);
virtualMethods = Arrays.copyOf(virtualMethods, virtualMethods.length + 1);
virtualMethods[virtualMethods.length - 1] = virtualMethod;
}
@Override
void addDirectMethod(DexEncodedMethod directMethod) {
assert belongsToDirectPool(directMethod);
directMethods = Arrays.copyOf(directMethods, directMethods.length + 1);
directMethods[directMethods.length - 1] = directMethod;
}
@Override
public DexEncodedMethod replaceDirectMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
for (int i = 0; i < directMethods.length; i++) {
DexEncodedMethod directMethod = directMethods[i];
if (method.match(directMethod)) {
DexEncodedMethod newMethod = replacement.apply(directMethod);
assert belongsToDirectPool(newMethod);
directMethods[i] = newMethod;
return newMethod;
}
}
return null;
}
@Override
public DexEncodedMethod replaceDirectMethodWithVirtualMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
for (int i = 0; i < directMethods.length; i++) {
DexEncodedMethod directMethod = directMethods[i];
if (method.match(directMethod)) {
DexEncodedMethod newMethod = replacement.apply(directMethod);
assert belongsToVirtualPool(newMethod);
removeDirectMethod(i);
addVirtualMethod(newMethod);
return newMethod;
}
}
return null;
}
@Override
public void replaceMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
replaceDirectMethods(replacement);
replaceVirtualMethods(replacement);
}
@Override
public void replaceDirectMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
for (int i = 0; i < directMethods.length; i++) {
DexEncodedMethod method = directMethods[i];
DexEncodedMethod newMethod = replacement.apply(method);
assert newMethod != null;
if (method != newMethod) {
assert belongsToDirectPool(newMethod);
directMethods[i] = newMethod;
}
}
}
@Override
public void replaceVirtualMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
for (int i = 0; i < virtualMethods.length; i++) {
DexEncodedMethod method = virtualMethods[i];
DexEncodedMethod newMethod = replacement.apply(method);
if (method != newMethod) {
assert belongsToVirtualPool(newMethod);
virtualMethods[i] = newMethod;
}
}
}
}