1// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4package com.android.tools.r8.graph;
5
6import com.android.tools.r8.errors.InternalCompilerError;
7import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
8import com.android.tools.r8.utils.InternalOptions;
9import java.util.List;
10import org.objectweb.asm.Type;
11
12/**
13 * Common structures used while reading in a Java application from jar files.
14 *
15 * The primary use of this class is to canonicalize dex items during read.
16 * The addition of classes to the builder also takes place through this class.
17 * It does not currently support multithreaded reading.
18 */
19public class JarApplicationReader {
20  public final InternalOptions options;
21
22  public JarApplicationReader(InternalOptions options) {
23    this.options = options;
24  }
25
26  public DexItemFactory getFactory() {
27    return options.itemFactory;
28  }
29
30  public DexString getString(String string) {
31    return options.itemFactory.createString(string);
32  }
33
34  public DexType getType(Type type) {
35    return getTypeFromDescriptor(type.getDescriptor());
36  }
37
38  public DexType getTypeFromName(String name) {
39    assert isValidInternalName(name);
40    return getType(Type.getObjectType(name));
41  }
42
43  public DexType getTypeFromDescriptor(String desc) {
44    assert isValidDescriptor(desc);
45    return options.itemFactory.createType(getString(desc));
46  }
47
48  public DexTypeList getTypeListFromNames(String[] names) {
49    if (names.length == 0) {
50      return DexTypeList.empty();
51    }
52    DexType[] types = new DexType[names.length];
53    for (int i = 0; i < names.length; i++) {
54      types[i] = getTypeFromName(names[i]);
55    }
56    return new DexTypeList(types);
57  }
58
59  public DexTypeList getTypeListFromDescriptors(String[] descriptors) {
60    if (descriptors.length == 0) {
61      return DexTypeList.empty();
62    }
63    DexType[] types = new DexType[descriptors.length];
64    for (int i = 0; i < descriptors.length; i++) {
65      types[i] = getTypeFromDescriptor(descriptors[i]);
66    }
67    return new DexTypeList(types);
68  }
69
70  public DexField getField(String owner, String name, String desc) {
71    return getField(getTypeFromName(owner), name, desc);
72  }
73
74  public DexField getField(DexType owner, String name, String desc) {
75    return options.itemFactory.createField(owner, getTypeFromDescriptor(desc), getString(name));
76  }
77
78  public DexMethod getMethod(String owner, String name, String desc) {
79    return getMethod(getTypeFromName(owner), name, desc);
80  }
81
82  public DexMethod getMethod(DexType owner, String name, String desc) {
83    return options.itemFactory.createMethod(owner, getProto(desc), getString(name));
84  }
85
86  public DexCallSite getCallSite(String methodName, String methodProto,
87      DexMethodHandle bootstrapMethod, List<DexValue> bootstrapArgs) {
88    return options.itemFactory.createCallSite(
89        getString(methodName), getProto(methodProto), bootstrapMethod, bootstrapArgs);
90  }
91
92  public DexMethodHandle getMethodHandle(
93      MethodHandleType type, Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod) {
94    return options.itemFactory.createMethodHandle(type, fieldOrMethod);
95  }
96
97  public DexProto getProto(String desc) {
98    assert isValidDescriptor(desc);
99    Type returnType = Type.getReturnType(desc);
100    Type[] arguments = Type.getArgumentTypes(desc);
101
102    StringBuilder shortyDescriptor = new StringBuilder();
103    String[] argumentDescriptors = new String[arguments.length];
104    shortyDescriptor.append(getShortyDescriptor(returnType));
105    for (int i = 0; i < arguments.length; i++) {
106      shortyDescriptor.append(getShortyDescriptor(arguments[i]));
107      argumentDescriptors[i] = arguments[i].getDescriptor();
108    }
109    DexProto proto = options.itemFactory.createProto(
110        getString(shortyDescriptor.toString()),
111        getTypeFromDescriptor(returnType.getDescriptor()),
112        getTypeListFromDescriptors(argumentDescriptors));
113    return proto;
114  }
115
116  private static String getShortyDescriptor(Type type) {
117    switch (type.getSort()) {
118      case Type.METHOD:
119        throw new InternalCompilerError("Cannot produce a shorty decriptor for methods");
120      case Type.ARRAY:
121      case Type.OBJECT:
122        return "L";
123      default:
124        return type.getDescriptor();
125    }
126  }
127
128  private boolean isValidDescriptor(String desc) {
129    return Type.getType(desc).getDescriptor().equals(desc);
130  }
131
132  private boolean isValidInternalName(String name) {
133    return Type.getObjectType(name).getInternalName().equals(name);
134  }
135}
136