• 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.lower;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.turbine.binder.bound.SourceTypeBoundClass;
21 import com.google.turbine.binder.bound.TypeBoundClass;
22 import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
23 import com.google.turbine.binder.env.Env;
24 import com.google.turbine.binder.sym.ClassSymbol;
25 import com.google.turbine.binder.sym.TyVarSymbol;
26 import com.google.turbine.bytecode.sig.Sig;
27 import com.google.turbine.bytecode.sig.Sig.ClassSig;
28 import com.google.turbine.bytecode.sig.Sig.ClassTySig;
29 import com.google.turbine.bytecode.sig.Sig.LowerBoundTySig;
30 import com.google.turbine.bytecode.sig.Sig.MethodSig;
31 import com.google.turbine.bytecode.sig.Sig.SimpleClassTySig;
32 import com.google.turbine.bytecode.sig.Sig.TySig;
33 import com.google.turbine.bytecode.sig.Sig.UpperBoundTySig;
34 import com.google.turbine.bytecode.sig.SigWriter;
35 import com.google.turbine.model.TurbineFlag;
36 import com.google.turbine.model.TurbineTyKind;
37 import com.google.turbine.type.Type;
38 import com.google.turbine.type.Type.ArrayTy;
39 import com.google.turbine.type.Type.ClassTy;
40 import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
41 import com.google.turbine.type.Type.PrimTy;
42 import com.google.turbine.type.Type.TyKind;
43 import com.google.turbine.type.Type.TyVar;
44 import com.google.turbine.type.Type.WildTy;
45 import java.util.Iterator;
46 import java.util.LinkedHashSet;
47 import java.util.Map;
48 import java.util.Set;
49 
50 /** Translator from {@link Type}s to {@link Sig}natures. */
51 public class LowerSignature {
52 
53   final Set<ClassSymbol> classes = new LinkedHashSet<>();
54 
55   /** Translates types to signatures. */
signature(Type ty)56   public Sig.TySig signature(Type ty) {
57     switch (ty.tyKind()) {
58       case CLASS_TY:
59         return classTySig((Type.ClassTy) ty);
60       case TY_VAR:
61         return tyVarSig((TyVar) ty);
62       case ARRAY_TY:
63         return arrayTySig((ArrayTy) ty);
64       case PRIM_TY:
65         return refBaseTy((PrimTy) ty);
66       case VOID_TY:
67         return Sig.VOID;
68       case WILD_TY:
69         return wildTy((WildTy) ty);
70       default:
71         throw new AssertionError(ty.tyKind());
72     }
73   }
74 
refBaseTy(PrimTy t)75   private Sig.BaseTySig refBaseTy(PrimTy t) {
76     return new Sig.BaseTySig(t.primkind());
77   }
78 
arrayTySig(ArrayTy t)79   private Sig.ArrayTySig arrayTySig(ArrayTy t) {
80     return new Sig.ArrayTySig(signature(t.elementType()));
81   }
82 
tyVarSig(TyVar t)83   private Sig.TyVarSig tyVarSig(TyVar t) {
84     return new Sig.TyVarSig(t.sym().name());
85   }
86 
classTySig(ClassTy t)87   private ClassTySig classTySig(ClassTy t) {
88     classes.add(t.sym());
89     ImmutableList.Builder<SimpleClassTySig> classes = ImmutableList.builder();
90     Iterator<SimpleClassTy> it = t.classes().iterator();
91     SimpleClassTy curr = it.next();
92     while (curr.targs().isEmpty() && it.hasNext()) {
93       curr = it.next();
94     }
95     String pkg;
96     String name;
97     int idx = curr.sym().binaryName().lastIndexOf('/');
98     if (idx == -1) {
99       pkg = "";
100       name = curr.sym().binaryName();
101     } else {
102       pkg = curr.sym().binaryName().substring(0, idx);
103       name = curr.sym().binaryName().substring(idx + 1);
104     }
105     classes.add(new Sig.SimpleClassTySig(name, tyArgSigs(curr)));
106     while (it.hasNext()) {
107       SimpleClassTy outer = curr;
108       curr = it.next();
109       String shortname = curr.sym().binaryName().substring(outer.sym().binaryName().length() + 1);
110       classes.add(new Sig.SimpleClassTySig(shortname, tyArgSigs(curr)));
111     }
112     return new ClassTySig(pkg, classes.build());
113   }
114 
tyArgSigs(SimpleClassTy part)115   private ImmutableList<TySig> tyArgSigs(SimpleClassTy part) {
116     ImmutableList.Builder<TySig> tyargs = ImmutableList.builder();
117     for (Type targ : part.targs()) {
118       tyargs.add(signature(targ));
119     }
120     return tyargs.build();
121   }
122 
wildTy(WildTy ty)123   private TySig wildTy(WildTy ty) {
124     switch (ty.boundKind()) {
125       case NONE:
126         return new Sig.WildTyArgSig();
127       case UPPER:
128         return new UpperBoundTySig(signature(((Type.WildUpperBoundedTy) ty).bound()));
129       case LOWER:
130         return new LowerBoundTySig(signature(((Type.WildLowerBoundedTy) ty).bound()));
131       default:
132         throw new AssertionError(ty.boundKind());
133     }
134   }
135 
136   /**
137    * Produces a method signature attribute for a generic method, or {@code null} if the signature is
138    * unnecessary.
139    */
methodSignature( Env<ClassSymbol, TypeBoundClass> env, SourceTypeBoundClass.MethodInfo method, ClassSymbol sym)140   public String methodSignature(
141       Env<ClassSymbol, TypeBoundClass> env,
142       SourceTypeBoundClass.MethodInfo method,
143       ClassSymbol sym) {
144     if (!needsMethodSig(sym, env, method)) {
145       return null;
146     }
147     ImmutableList<Sig.TyParamSig> typarams = tyParamSig(method.tyParams(), env);
148     ImmutableList.Builder<Sig.TySig> fparams = ImmutableList.builder();
149     for (SourceTypeBoundClass.ParamInfo t : method.parameters()) {
150       if (t.synthetic()) {
151         continue;
152       }
153       fparams.add(signature(t.type()));
154     }
155     Sig.TySig ret = signature(method.returnType());
156     ImmutableList.Builder<Sig.TySig> excn = ImmutableList.builder();
157     boolean needsExnSig = false;
158     for (Type e : method.exceptions()) {
159       if (needsSig(e)) {
160         needsExnSig = true;
161         break;
162       }
163     }
164     if (needsExnSig) {
165       for (Type e : method.exceptions()) {
166         excn.add(signature(e));
167       }
168     }
169     MethodSig sig = new MethodSig(typarams, fparams.build(), ret, excn.build());
170     return SigWriter.method(sig);
171   }
172 
needsMethodSig( ClassSymbol sym, Env<ClassSymbol, TypeBoundClass> env, SourceTypeBoundClass.MethodInfo m)173   private boolean needsMethodSig(
174       ClassSymbol sym, Env<ClassSymbol, TypeBoundClass> env, SourceTypeBoundClass.MethodInfo m) {
175     if ((env.get(sym).access() & TurbineFlag.ACC_ENUM) == TurbineFlag.ACC_ENUM
176         && m.name().equals("<init>")) {
177       // JDK-8024694: javac always expects signature attribute for enum constructors
178       return true;
179     }
180     if ((m.access() & TurbineFlag.ACC_SYNTH_CTOR) == TurbineFlag.ACC_SYNTH_CTOR) {
181       return false;
182     }
183     if (!m.tyParams().isEmpty()) {
184       return true;
185     }
186     if (m.returnType() != null && needsSig(m.returnType())) {
187       return true;
188     }
189     for (SourceTypeBoundClass.ParamInfo t : m.parameters()) {
190       if (t.synthetic()) {
191         continue;
192       }
193       if (needsSig(t.type())) {
194         return true;
195       }
196     }
197     for (Type t : m.exceptions()) {
198       if (needsSig(t)) {
199         return true;
200       }
201     }
202     return false;
203   }
204 
205   /**
206    * Produces a class signature attribute for a generic class, or {@code null} if the signature is
207    * unnecessary.
208    */
classSignature(SourceTypeBoundClass info, Env<ClassSymbol, TypeBoundClass> env)209   public String classSignature(SourceTypeBoundClass info, Env<ClassSymbol, TypeBoundClass> env) {
210     if (!classNeedsSig(info)) {
211       return null;
212     }
213     ImmutableList<Sig.TyParamSig> typarams = tyParamSig(info.typeParameterTypes(), env);
214 
215     ClassTySig xtnd = null;
216     if (info.superClassType() != null) {
217       xtnd = classTySig((ClassTy) info.superClassType());
218     }
219     ImmutableList.Builder<ClassTySig> impl = ImmutableList.builder();
220     for (Type i : info.interfaceTypes()) {
221       impl.add(classTySig((ClassTy) i));
222     }
223     ClassSig sig = new ClassSig(typarams, xtnd, impl.build());
224     return SigWriter.classSig(sig);
225   }
226 
227   /**
228    * A field signature, or {@code null} if the descriptor provides all necessary type information.
229    */
fieldSignature(Type type)230   public String fieldSignature(Type type) {
231     return needsSig(type) ? SigWriter.type(signature(type)) : null;
232   }
233 
classNeedsSig(SourceTypeBoundClass ci)234   private boolean classNeedsSig(SourceTypeBoundClass ci) {
235     if (!ci.typeParameters().isEmpty()) {
236       return true;
237     }
238     if (ci.superClassType() != null && needsSig(ci.superClassType())) {
239       return true;
240     }
241     for (Type i : ci.interfaceTypes()) {
242       if (needsSig(i)) {
243         return true;
244       }
245     }
246     return false;
247   }
248 
needsSig(Type ty)249   private boolean needsSig(Type ty) {
250     switch (ty.tyKind()) {
251       case PRIM_TY:
252       case VOID_TY:
253         return false;
254       case CLASS_TY:
255         {
256           for (SimpleClassTy s : ((ClassTy) ty).classes()) {
257             if (!s.targs().isEmpty()) {
258               return true;
259             }
260           }
261           return false;
262         }
263       case ARRAY_TY:
264         return needsSig(((ArrayTy) ty).elementType());
265       case TY_VAR:
266         return true;
267       default:
268         throw new AssertionError(ty.tyKind());
269     }
270   }
271 
tyParamSig( Map<TyVarSymbol, TyVarInfo> px, Env<ClassSymbol, TypeBoundClass> env)272   private ImmutableList<Sig.TyParamSig> tyParamSig(
273       Map<TyVarSymbol, TyVarInfo> px, Env<ClassSymbol, TypeBoundClass> env) {
274     ImmutableList.Builder<Sig.TyParamSig> result = ImmutableList.builder();
275     for (Map.Entry<TyVarSymbol, SourceTypeBoundClass.TyVarInfo> entry : px.entrySet()) {
276       result.add(tyParamSig(entry.getKey(), entry.getValue(), env));
277     }
278     return result.build();
279   }
280 
tyParamSig( TyVarSymbol sym, SourceTypeBoundClass.TyVarInfo info, Env<ClassSymbol, TypeBoundClass> env)281   private Sig.TyParamSig tyParamSig(
282       TyVarSymbol sym, SourceTypeBoundClass.TyVarInfo info, Env<ClassSymbol, TypeBoundClass> env) {
283 
284     String identifier = sym.name();
285     Sig.TySig cbound = null;
286     ImmutableList.Builder<Sig.TySig> ibounds = ImmutableList.builder();
287     if (info.bound().bounds().isEmpty()) {
288       cbound =
289           new ClassTySig(
290               "java/lang", ImmutableList.of(new SimpleClassTySig("Object", ImmutableList.of())));
291     } else {
292       boolean first = true;
293       for (Type bound : info.bound().bounds()) {
294         TySig sig = signature(bound);
295         if (first) {
296           if (!isInterface(bound, env)) {
297             cbound = sig;
298             continue;
299           }
300         }
301         ibounds.add(sig);
302         first = false;
303       }
304     }
305     return new Sig.TyParamSig(identifier, cbound, ibounds.build());
306   }
307 
isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env)308   private boolean isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env) {
309     return type.tyKind() == TyKind.CLASS_TY
310         && env.get(((ClassTy) type).sym()).kind() == TurbineTyKind.INTERFACE;
311   }
312 
descriptor(ClassSymbol sym)313   public String descriptor(ClassSymbol sym) {
314     classes.add(sym);
315     return sym.binaryName();
316   }
317 
objectType(ClassSymbol sym)318   String objectType(ClassSymbol sym) {
319     return "L" + descriptor(sym) + ";";
320   }
321 }
322