blob: 1d73fdc8a41a1883c7cee60b3297fd6985ad0a09 [file] [log] [blame]
// Copyright (c) 2019, 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.optimize.classinliner;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BooleanSupplier;
class ClassInlinerReceiverSet {
private final Value root;
private final Set<Value> receiverAliases;
// Set of values that are not allowed to become an alias of the receiver.
private final Set<Value> illegalReceiverAliases = Sets.newIdentityHashSet();
// Set of values that are allowed to become an alias of the receiver under certain circumstances.
private final Map<Value, List<BooleanSupplier>> deferredAliasValidityChecks =
new IdentityHashMap<>();
ClassInlinerReceiverSet(Value root) {
this.receiverAliases = SetUtils.newIdentityHashSet(root);
this.root = root;
}
boolean addReceiverAlias(Value alias) {
if (isIllegalReceiverAlias(alias)) {
return false; // Not allowed.
}
// All checks passed.
deferredAliasValidityChecks.remove(alias);
boolean changed;
changed = receiverAliases.add(alias);
// Verify that the state changed. Otherwise, we are analyzing the same instruction more than
// once.
assert changed : alias.toString() + " already added as an alias";
return true;
}
boolean addIllegalReceiverAlias(Value value) {
if (isReceiverAlias(value)) {
return false;
}
illegalReceiverAliases.add(value);
// Since `value` is never allowed as a receiver, there is no need to keep the validity checks
// around.
deferredAliasValidityChecks.remove(value);
return true;
}
void addDeferredAliasValidityCheck(Value value, BooleanSupplier deferredValidityCheck) {
assert !isReceiverAlias(value);
// Only add the deferred validity check if `value` may be allowed as a receiver (i.e., it is not
// already illegal).
if (illegalReceiverAliases.contains(value)) {
assert !deferredAliasValidityChecks.containsKey(value);
} else {
deferredAliasValidityChecks
.computeIfAbsent(value, ignore -> new ArrayList<>())
.add(deferredValidityCheck);
}
}
boolean isReceiverAlias(Value value) {
return isDefiniteReceiverAlias(value);
}
boolean isDefiniteReceiverAlias(Value value) {
return receiverAliases.contains(value);
}
private boolean isIllegalReceiverAlias(Value value) {
if (illegalReceiverAliases.contains(value)) {
return true;
}
List<BooleanSupplier> deferredValidityChecks = deferredAliasValidityChecks.get(value);
if (deferredValidityChecks != null) {
for (BooleanSupplier deferredValidityCheck : deferredValidityChecks) {
if (!deferredValidityCheck.getAsBoolean()) {
return true;
}
}
}
return false;
}
void reset() {
deferredAliasValidityChecks.clear();
receiverAliases.clear();
receiverAliases.add(root);
}
}