• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.binder.bytecode;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.turbine.binder.bound.EnumConstantValue;
24 import com.google.turbine.binder.bound.ModuleInfo;
25 import com.google.turbine.binder.bound.TurbineAnnotationValue;
26 import com.google.turbine.binder.bound.TurbineClassValue;
27 import com.google.turbine.binder.sym.ClassSymbol;
28 import com.google.turbine.binder.sym.FieldSymbol;
29 import com.google.turbine.binder.sym.TyVarSymbol;
30 import com.google.turbine.bytecode.ClassFile;
31 import com.google.turbine.bytecode.ClassFile.AnnotationInfo;
32 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
33 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ArrayValue;
34 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstTurbineClassValue;
35 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstValue;
36 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue;
37 import com.google.turbine.bytecode.ClassReader;
38 import com.google.turbine.bytecode.sig.Sig;
39 import com.google.turbine.bytecode.sig.Sig.LowerBoundTySig;
40 import com.google.turbine.bytecode.sig.Sig.UpperBoundTySig;
41 import com.google.turbine.bytecode.sig.Sig.WildTySig;
42 import com.google.turbine.bytecode.sig.SigParser;
43 import com.google.turbine.model.Const;
44 import com.google.turbine.model.Const.ArrayInitValue;
45 import com.google.turbine.model.Const.Value;
46 import com.google.turbine.type.AnnoInfo;
47 import com.google.turbine.type.Type;
48 import java.util.ArrayList;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.function.Function;
52 import java.util.function.Supplier;
53 
54 /** Bind {@link Type}s from bytecode. */
55 public final class BytecodeBinder {
56 
bindClassTy(Sig.ClassTySig sig, Function<String, TyVarSymbol> scope)57   static Type.ClassTy bindClassTy(Sig.ClassTySig sig, Function<String, TyVarSymbol> scope) {
58     StringBuilder sb = new StringBuilder(sig.pkg());
59     boolean first = true;
60     List<Type.ClassTy.SimpleClassTy> classes = new ArrayList<>();
61     for (Sig.SimpleClassTySig s : sig.classes()) {
62       sb.append(first ? '/' : '$');
63       sb.append(s.simpleName());
64       ClassSymbol sym = new ClassSymbol(sb.toString());
65 
66       ImmutableList.Builder<Type> tyArgs = ImmutableList.builder();
67       for (Sig.TySig arg : s.tyArgs()) {
68         tyArgs.add(bindTy(arg, scope));
69       }
70 
71       classes.add(Type.ClassTy.SimpleClassTy.create(sym, tyArgs.build(), ImmutableList.of()));
72       first = false;
73     }
74     return Type.ClassTy.create(classes);
75   }
76 
wildTy(WildTySig sig, Function<String, TyVarSymbol> scope)77   private static Type wildTy(WildTySig sig, Function<String, TyVarSymbol> scope) {
78     switch (sig.boundKind()) {
79       case NONE:
80         return Type.WildUnboundedTy.create(ImmutableList.of());
81       case LOWER:
82         return Type.WildLowerBoundedTy.create(
83             bindTy(((LowerBoundTySig) sig).bound(), scope), ImmutableList.of());
84       case UPPER:
85         return Type.WildUpperBoundedTy.create(
86             bindTy(((UpperBoundTySig) sig).bound(), scope), ImmutableList.of());
87     }
88     throw new AssertionError(sig.boundKind());
89   }
90 
bindTy(Sig.TySig sig, Function<String, TyVarSymbol> scope)91   static Type bindTy(Sig.TySig sig, Function<String, TyVarSymbol> scope) {
92     switch (sig.kind()) {
93       case BASE_TY_SIG:
94         return Type.PrimTy.create(((Sig.BaseTySig) sig).type(), ImmutableList.of());
95       case CLASS_TY_SIG:
96         return bindClassTy((Sig.ClassTySig) sig, scope);
97       case TY_VAR_SIG:
98         return Type.TyVar.create(scope.apply(((Sig.TyVarSig) sig).name()), ImmutableList.of());
99       case ARRAY_TY_SIG:
100         return bindArrayTy((Sig.ArrayTySig) sig, scope);
101       case WILD_TY_SIG:
102         return wildTy((WildTySig) sig, scope);
103       case VOID_TY_SIG:
104         return Type.VOID;
105     }
106     throw new AssertionError(sig.kind());
107   }
108 
bindArrayTy(Sig.ArrayTySig arrayTySig, Function<String, TyVarSymbol> scope)109   private static Type bindArrayTy(Sig.ArrayTySig arrayTySig, Function<String, TyVarSymbol> scope) {
110     return Type.ArrayTy.create(bindTy(arrayTySig.elementType(), scope), ImmutableList.of());
111   }
112 
bindValue(ElementValue value)113   public static Const bindValue(ElementValue value) {
114     switch (value.kind()) {
115       case ENUM:
116         return bindEnumValue((EnumConstValue) value);
117       case CONST:
118         return ((ConstValue) value).value();
119       case ARRAY:
120         return bindArrayValue((ArrayValue) value);
121       case CLASS:
122         return new TurbineClassValue(
123             bindTy(
124                 new SigParser(((ConstTurbineClassValue) value).className()).parseType(),
125                 x -> {
126                   throw new IllegalStateException(x);
127                 }));
128       case ANNOTATION:
129         return bindAnnotationValue(((ElementValue.ConstTurbineAnnotationValue) value).annotation());
130     }
131     throw new AssertionError(value.kind());
132   }
133 
bindAnnotationValue(AnnotationInfo value)134   static TurbineAnnotationValue bindAnnotationValue(AnnotationInfo value) {
135     ClassSymbol sym = asClassSymbol(value.typeName());
136     ImmutableMap.Builder<String, Const> values = ImmutableMap.builder();
137     for (Map.Entry<String, ElementValue> e : value.elementValuePairs().entrySet()) {
138       values.put(e.getKey(), bindValue(e.getValue()));
139     }
140     return new TurbineAnnotationValue(new AnnoInfo(null, sym, null, values.buildOrThrow()));
141   }
142 
bindAnnotations(List<AnnotationInfo> input)143   static ImmutableList<AnnoInfo> bindAnnotations(List<AnnotationInfo> input) {
144     ImmutableList.Builder<AnnoInfo> result = ImmutableList.builder();
145     for (AnnotationInfo annotation : input) {
146       TurbineAnnotationValue anno = bindAnnotationValue(annotation);
147       if (!shouldSkip(anno)) {
148         result.add(anno.info());
149       }
150     }
151     return result.build();
152   }
153 
shouldSkip(TurbineAnnotationValue anno)154   private static boolean shouldSkip(TurbineAnnotationValue anno) {
155     // ct.sym contains fake annotations without corresponding class files.
156     return anno.sym().equals(ClassSymbol.PROFILE_ANNOTATION)
157         || anno.sym().equals(ClassSymbol.PROPRIETARY_ANNOTATION);
158   }
159 
asClassSymbol(String s)160   private static ClassSymbol asClassSymbol(String s) {
161     return new ClassSymbol(s.substring(1, s.length() - 1));
162   }
163 
bindArrayValue(ArrayValue value)164   private static Const bindArrayValue(ArrayValue value) {
165     ImmutableList.Builder<Const> elements = ImmutableList.builder();
166     for (ElementValue element : value.elements()) {
167       elements.add(bindValue(element));
168     }
169     return new ArrayInitValue(elements.build());
170   }
171 
bindConstValue(Type type, Const.Value value)172   public static Const.Value bindConstValue(Type type, Const.Value value) {
173     if (type.tyKind() != Type.TyKind.PRIM_TY) {
174       return value;
175     }
176     // Deficient numberic types and booleans are all stored as ints in the class file,
177     // coerce them to the target type.
178     // TODO(b/32626659): this is not bug-compatible with javac
179     switch (((Type.PrimTy) type).primkind()) {
180       case CHAR:
181         return new Const.CharValue((char) asInt(value));
182       case SHORT:
183         return new Const.ShortValue((short) asInt(value));
184       case BOOLEAN:
185         // boolean constants are encoded as integers
186         return new Const.BooleanValue(asInt(value) != 0);
187       case BYTE:
188         return new Const.ByteValue((byte) asInt(value));
189       default:
190         return value;
191     }
192   }
193 
asInt(Value value)194   private static int asInt(Value value) {
195     return ((Const.IntValue) value).value();
196   }
197 
bindEnumValue(EnumConstValue value)198   private static Const bindEnumValue(EnumConstValue value) {
199     return new EnumConstantValue(
200         new FieldSymbol(asClassSymbol(value.typeName()), value.constName()));
201   }
202 
203   /**
204    * Returns a {@link ModuleInfo} given a module-info class file. Currently only the module's name,
205    * version, and flags are populated, since the directives are not needed by turbine at compile
206    * time.
207    */
bindModuleInfo(String path, Supplier<byte[]> bytes)208   public static ModuleInfo bindModuleInfo(String path, Supplier<byte[]> bytes) {
209     ClassFile classFile = ClassReader.read(path, bytes.get());
210     ClassFile.ModuleInfo module = classFile.module();
211     requireNonNull(module, path);
212     return new ModuleInfo(
213         module.name(),
214         module.version(),
215         module.flags(),
216         /* annos= */ ImmutableList.of(),
217         /* requires= */ ImmutableList.of(),
218         /* exports= */ ImmutableList.of(),
219         /* opens= */ ImmutableList.of(),
220         /* uses= */ ImmutableList.of(),
221         /* provides= */ ImmutableList.of());
222   }
223 
BytecodeBinder()224   private BytecodeBinder() {}
225 }
226