blob: 67e7b5ba143829f6bec8d7db2b79db15cee3d31e [file] [log] [blame]
// Copyright (c) 2016, 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.graph.DexMethodHandle.MethodHandleType;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.objectweb.asm.Type;
/**
* Common structures used while reading in a Java application from jar files.
*
* The primary use of this class is to canonicalize dex items during read.
* The addition of classes to the builder also takes place through this class.
* It does not currently support multithreaded reading.
*/
public class JarApplicationReader {
public final InternalOptions options;
private final ConcurrentHashMap<String, Type> asmObjectTypeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Type> asmTypeCache = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, DexString> stringCache = new ConcurrentHashMap<>();
private final Map<String, String> typeDescriptorMap;
public JarApplicationReader(InternalOptions options) {
this.options = options;
typeDescriptorMap = ApplicationReaderMap.getDescriptorMap(options);
}
public Type getAsmObjectType(String name) {
return asmObjectTypeCache.computeIfAbsent(name, Type::getObjectType);
}
public Type getAsmType(String name) {
return asmTypeCache.computeIfAbsent(name, Type::getType);
}
public DexItemFactory getFactory() {
return options.itemFactory;
}
public DexString getString(String string) {
return stringCache.computeIfAbsent(string, options.itemFactory::createString);
}
public DexType getType(Type type) {
return getTypeFromDescriptor(type.getDescriptor());
}
public DexType getTypeFromName(String name) {
assert isValidInternalName(name);
return getType(getAsmObjectType(name));
}
public DexType getTypeFromDescriptor(String desc) {
assert isValidDescriptor(desc);
String actualDesc = typeDescriptorMap.getOrDefault(desc, desc);
return options.itemFactory.createType(getString(actualDesc));
}
public DexTypeList getTypeListFromNames(String[] names) {
if (names.length == 0) {
return DexTypeList.empty();
}
DexType[] types = new DexType[names.length];
for (int i = 0; i < names.length; i++) {
types[i] = getTypeFromName(names[i]);
}
return new DexTypeList(types);
}
public DexTypeList getTypeListFromDescriptors(String[] descriptors) {
if (descriptors.length == 0) {
return DexTypeList.empty();
}
DexType[] types = new DexType[descriptors.length];
for (int i = 0; i < descriptors.length; i++) {
types[i] = getTypeFromDescriptor(descriptors[i]);
}
return new DexTypeList(types);
}
public DexField getField(String owner, String name, String desc) {
return getField(getTypeFromName(owner), name, desc);
}
public DexField getField(DexType owner, String name, String desc) {
return options.itemFactory.createField(owner, getTypeFromDescriptor(desc), getString(name));
}
public DexMethod getMethod(String owner, String name, String desc) {
return getMethod(getTypeFromName(owner), name, desc);
}
public DexMethod getMethod(DexType owner, String name, String desc) {
return options.itemFactory.createMethod(owner, getProto(desc), getString(name));
}
public DexCallSite getCallSite(String methodName, String methodProto,
DexMethodHandle bootstrapMethod, List<DexValue> bootstrapArgs) {
return options.itemFactory.createCallSite(
getString(methodName), getProto(methodProto), bootstrapMethod, bootstrapArgs);
}
public DexMethodHandle getMethodHandle(
MethodHandleType type,
DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod,
boolean isInterface) {
return options.itemFactory.createMethodHandle(type, fieldOrMethod, isInterface);
}
public DexProto getProto(String desc) {
assert isValidDescriptor(desc);
String returnTypeDescriptor = DescriptorUtils.getReturnTypeDescriptor(desc);
String[] argumentDescriptors = DescriptorUtils.getArgumentTypeDescriptors(desc);
StringBuilder shortyDescriptor = new StringBuilder();
shortyDescriptor.append(getShortyDescriptor(returnTypeDescriptor));
for (int i = 0; i < argumentDescriptors.length; i++) {
shortyDescriptor.append(getShortyDescriptor(argumentDescriptors[i]));
}
DexProto proto =
options.itemFactory.createProto(
getTypeFromDescriptor(returnTypeDescriptor),
getTypeListFromDescriptors(argumentDescriptors),
getString(shortyDescriptor.toString()));
return proto;
}
private static String getShortyDescriptor(String descriptor) {
if (descriptor.length() == 1) {
return descriptor;
}
assert descriptor.charAt(0) == 'L' || descriptor.charAt(0) == '[';
return "L";
}
private boolean isValidDescriptor(String desc) {
return getAsmType(desc).getDescriptor().equals(desc);
}
private boolean isValidInternalName(String name) {
return getAsmObjectType(name).getInternalName().equals(name);
}
public Type getReturnType(final String methodDescriptor) {
return getAsmType(DescriptorUtils.getReturnTypeDescriptor(methodDescriptor));
}
}