
main.java.com.debughelper.tools.r8.naming.NamingState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of debughelper Show documentation
Show all versions of debughelper Show documentation
A gradle plugin help to debug android lib module include native code.
The newest version!
// 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.debughelper.tools.r8.naming;
import com.debughelper.tools.r8.graph.CachedHashValueDexItem;
import com.debughelper.tools.r8.graph.DexItemFactory;
import com.debughelper.tools.r8.graph.DexString;
import com.debughelper.tools.r8.utils.StringUtils;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
class NamingState {
private final NamingState parent;
private final Map> usedNames = new HashMap<>();
private final DexItemFactory itemFactory;
private final ImmutableList dictionary;
private final Function keyTransform;
private final boolean useUniqueMemberNames;
static NamingState createRoot(
DexItemFactory itemFactory,
ImmutableList dictionary,
Function keyTransform,
boolean useUniqueMemberNames) {
return new NamingState<>(null, itemFactory, dictionary, keyTransform, useUniqueMemberNames);
}
private NamingState(
NamingState parent,
DexItemFactory itemFactory,
ImmutableList dictionary,
Function keyTransform,
boolean useUniqueMemberNames) {
this.parent = parent;
this.itemFactory = itemFactory;
this.dictionary = dictionary;
this.keyTransform = keyTransform;
this.useUniqueMemberNames = useUniqueMemberNames;
}
public NamingState createChild() {
return new NamingState<>(this, itemFactory, dictionary, keyTransform, useUniqueMemberNames);
}
private InternalState findInternalStateFor(ProtoType proto) {
KeyType key = keyTransform.apply(proto);
InternalState result = usedNames.get(key);
if (result == null && parent != null) {
result = parent.findInternalStateFor(proto);
}
return result;
}
private InternalState getOrCreateInternalStateFor(ProtoType proto) {
// TODO(herhut): Maybe allocate these sparsely and search via state chain.
KeyType key = keyTransform.apply(proto);
InternalState result = usedNames.get(key);
if (result == null) {
if (parent != null) {
InternalState parentState = parent.getOrCreateInternalStateFor(proto);
result = parentState.createChild();
} else {
result = new InternalState<>(itemFactory, null, dictionary);
}
usedNames.put(key, result);
}
return result;
}
private DexString getAssignedNameFor(DexString name, ProtoType proto) {
InternalState state = findInternalStateFor(proto);
if (state == null) {
return null;
}
return state.getAssignedNameFor(name, proto);
}
public DexString assignNewNameFor(DexString original, ProtoType proto, boolean markAsUsed) {
DexString result = getAssignedNameFor(original, proto);
if (result == null) {
InternalState state = getOrCreateInternalStateFor(proto);
result = state.getNameFor(original, proto, markAsUsed);
}
return result;
}
public void reserveName(DexString name, ProtoType proto) {
InternalState state = getOrCreateInternalStateFor(proto);
state.reserveName(name);
}
public boolean isReserved(DexString name, ProtoType proto) {
InternalState state = findInternalStateFor(proto);
if (state == null) {
return false;
}
return state.isReserved(name);
}
public boolean isAvailable(DexString original, ProtoType proto, DexString candidate) {
InternalState state = findInternalStateFor(proto);
if (state == null) {
return true;
}
assert state.getAssignedNameFor(original, proto) != candidate || useUniqueMemberNames;
return state.isAvailable(candidate);
}
public void addRenaming(DexString original, ProtoType proto, DexString newName) {
InternalState state = getOrCreateInternalStateFor(proto);
state.addRenaming(original, proto, newName);
}
private class InternalState {
private static final int INITIAL_NAME_COUNT = 1;
private final char[] EMPTY_CHAR_ARRARY = new char[0];
protected final DexItemFactory itemFactory;
private final InternalState parentInternalState;
private Set reservedNames = null;
private Table renamings = null;
private int nameCount;
private final Iterator dictionaryIterator;
private InternalState(
DexItemFactory itemFactory,
InternalState parentInternalState,
Iterator dictionaryIterator) {
this.itemFactory = itemFactory;
this.parentInternalState = parentInternalState;
this.nameCount =
parentInternalState == null ? INITIAL_NAME_COUNT : parentInternalState.nameCount;
this.dictionaryIterator = dictionaryIterator;
}
private InternalState(
DexItemFactory itemFactory,
InternalState parentInternalState,
List dictionary) {
this(itemFactory, parentInternalState, dictionary.iterator());
}
private boolean isReserved(DexString name) {
return (reservedNames != null && reservedNames.contains(name))
|| (parentInternalState != null && parentInternalState.isReserved(name));
}
private boolean isAvailable(DexString name) {
return !(renamings != null && renamings.containsValue(name))
&& !(reservedNames != null && reservedNames.contains(name))
&& (parentInternalState == null || parentInternalState.isAvailable(name));
}
InternalState createChild() {
return new InternalState<>(itemFactory, this, dictionaryIterator);
}
void reserveName(DexString name) {
if (reservedNames == null) {
reservedNames = Sets.newIdentityHashSet();
}
reservedNames.add(name);
}
DexString getAssignedNameFor(DexString original, InternalProtoType proto) {
DexString result = null;
if (renamings != null) {
if (useUniqueMemberNames) {
Map row = renamings.row(original);
if (row != null) {
// Either not renamed yet (0) or renamed (1). If renamed, return the same renamed name
// so that other members with the same name can be renamed to the same renamed name.
Set renamedNames = Sets.newHashSet(row.values());
assert renamedNames.size() <= 1;
result = Iterables.getOnlyElement(renamedNames, null);
}
} else {
result = renamings.get(original, proto);
}
}
if (result == null && parentInternalState != null) {
result = parentInternalState.getAssignedNameFor(original, proto);
}
return result;
}
DexString getNameFor(DexString original, InternalProtoType proto, boolean markAsUsed) {
DexString name = getAssignedNameFor(original, proto);
if (name != null) {
return name;
}
do {
name = itemFactory.createString(nextSuggestedName());
} while (!isAvailable(name));
if (markAsUsed) {
addRenaming(original, proto, name);
}
return name;
}
void addRenaming(DexString original, InternalProtoType proto, DexString newName) {
if (renamings == null) {
renamings = HashBasedTable.create();
}
renamings.put(original, proto, newName);
}
String nextSuggestedName() {
if (dictionaryIterator.hasNext()) {
return dictionaryIterator.next();
} else {
return StringUtils.numberToIdentifier(EMPTY_CHAR_ARRARY, nameCount++, false);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy