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 static com.google.common.collect.Iterables.getOnlyElement; 20 import static com.google.turbine.binder.DisambiguateTypeAnnotations.groupRepeated; 21 import static java.lang.Math.max; 22 import static java.util.Objects.requireNonNull; 23 24 import com.google.common.base.Function; 25 import com.google.common.collect.ImmutableList; 26 import com.google.common.collect.ImmutableMap; 27 import com.google.common.collect.ImmutableSet; 28 import com.google.turbine.binder.bound.EnumConstantValue; 29 import com.google.turbine.binder.bound.ModuleInfo.ExportInfo; 30 import com.google.turbine.binder.bound.ModuleInfo.OpenInfo; 31 import com.google.turbine.binder.bound.ModuleInfo.ProvideInfo; 32 import com.google.turbine.binder.bound.ModuleInfo.RequireInfo; 33 import com.google.turbine.binder.bound.ModuleInfo.UseInfo; 34 import com.google.turbine.binder.bound.SourceModuleInfo; 35 import com.google.turbine.binder.bound.SourceTypeBoundClass; 36 import com.google.turbine.binder.bound.TurbineAnnotationValue; 37 import com.google.turbine.binder.bound.TurbineClassValue; 38 import com.google.turbine.binder.bound.TypeBoundClass; 39 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo; 40 import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo; 41 import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo; 42 import com.google.turbine.binder.bound.TypeBoundClass.RecordComponentInfo; 43 import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo; 44 import com.google.turbine.binder.bytecode.BytecodeBoundClass; 45 import com.google.turbine.binder.env.CompoundEnv; 46 import com.google.turbine.binder.env.Env; 47 import com.google.turbine.binder.env.SimpleEnv; 48 import com.google.turbine.binder.sym.ClassSymbol; 49 import com.google.turbine.binder.sym.Symbol; 50 import com.google.turbine.binder.sym.TyVarSymbol; 51 import com.google.turbine.bytecode.ClassFile; 52 import com.google.turbine.bytecode.ClassFile.AnnotationInfo; 53 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue; 54 import com.google.turbine.bytecode.ClassFile.MethodInfo.ParameterInfo; 55 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo; 56 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.Target; 57 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TargetType; 58 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.ThrowsTarget; 59 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypePath; 60 import com.google.turbine.bytecode.ClassWriter; 61 import com.google.turbine.bytecode.sig.Sig; 62 import com.google.turbine.bytecode.sig.Sig.MethodSig; 63 import com.google.turbine.bytecode.sig.Sig.TySig; 64 import com.google.turbine.bytecode.sig.SigWriter; 65 import com.google.turbine.diag.SourceFile; 66 import com.google.turbine.diag.TurbineError; 67 import com.google.turbine.diag.TurbineError.ErrorKind; 68 import com.google.turbine.model.Const; 69 import com.google.turbine.model.TurbineFlag; 70 import com.google.turbine.model.TurbineTyKind; 71 import com.google.turbine.model.TurbineVisibility; 72 import com.google.turbine.options.LanguageVersion; 73 import com.google.turbine.type.AnnoInfo; 74 import com.google.turbine.type.Type; 75 import com.google.turbine.type.Type.ArrayTy; 76 import com.google.turbine.type.Type.ClassTy; 77 import com.google.turbine.type.Type.ClassTy.SimpleClassTy; 78 import com.google.turbine.type.Type.TyKind; 79 import com.google.turbine.type.Type.TyVar; 80 import com.google.turbine.type.Type.WildTy; 81 import com.google.turbine.types.Erasure; 82 import java.lang.annotation.RetentionPolicy; 83 import java.util.ArrayDeque; 84 import java.util.ArrayList; 85 import java.util.Deque; 86 import java.util.LinkedHashSet; 87 import java.util.List; 88 import java.util.Map; 89 import java.util.Set; 90 import org.jspecify.nullness.Nullable; 91 92 /** Lowering from bound classes to bytecode. */ 93 public class Lower { 94 95 /** The lowered compilation output. */ 96 public static class Lowered { 97 private final ImmutableMap<String, byte[]> bytes; 98 private final ImmutableSet<ClassSymbol> symbols; 99 Lowered(ImmutableMap<String, byte[]> bytes, ImmutableSet<ClassSymbol> symbols)100 public Lowered(ImmutableMap<String, byte[]> bytes, ImmutableSet<ClassSymbol> symbols) { 101 this.bytes = bytes; 102 this.symbols = symbols; 103 } 104 105 /** Returns the bytecode for classes in the compilation. */ bytes()106 public ImmutableMap<String, byte[]> bytes() { 107 return bytes; 108 } 109 110 /** Returns the set of all referenced symbols in the compilation. */ symbols()111 public ImmutableSet<ClassSymbol> symbols() { 112 return symbols; 113 } 114 } 115 116 /** Lowers all given classes to bytecode. */ lowerAll( LanguageVersion languageVersion, ImmutableMap<ClassSymbol, SourceTypeBoundClass> units, ImmutableList<SourceModuleInfo> modules, Env<ClassSymbol, BytecodeBoundClass> classpath)117 public static Lowered lowerAll( 118 LanguageVersion languageVersion, 119 ImmutableMap<ClassSymbol, SourceTypeBoundClass> units, 120 ImmutableList<SourceModuleInfo> modules, 121 Env<ClassSymbol, BytecodeBoundClass> classpath) { 122 CompoundEnv<ClassSymbol, TypeBoundClass> env = 123 CompoundEnv.<ClassSymbol, TypeBoundClass>of(classpath).append(new SimpleEnv<>(units)); 124 ImmutableMap.Builder<String, byte[]> result = ImmutableMap.builder(); 125 Set<ClassSymbol> symbols = new LinkedHashSet<>(); 126 // Output Java 8 bytecode at minimum, for type annotations 127 int majorVersion = max(languageVersion.majorVersion(), 52); 128 for (ClassSymbol sym : units.keySet()) { 129 result.put(sym.binaryName(), lower(units.get(sym), env, sym, symbols, majorVersion)); 130 } 131 if (modules.size() == 1) { 132 // single module mode: the module-info.class file is at the root 133 result.put("module-info", lower(getOnlyElement(modules), env, symbols, majorVersion)); 134 } else { 135 // multi-module mode: the output module-info.class are in a directory corresponding to their 136 // package 137 for (SourceModuleInfo module : modules) { 138 result.put( 139 module.name().replace('.', '/') + "/module-info", 140 lower(module, env, symbols, majorVersion)); 141 } 142 } 143 return new Lowered(result.buildOrThrow(), ImmutableSet.copyOf(symbols)); 144 } 145 146 /** Lowers a class to bytecode. */ lower( SourceTypeBoundClass info, Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, Set<ClassSymbol> symbols, int majorVersion)147 public static byte[] lower( 148 SourceTypeBoundClass info, 149 Env<ClassSymbol, TypeBoundClass> env, 150 ClassSymbol sym, 151 Set<ClassSymbol> symbols, 152 int majorVersion) { 153 return new Lower(env).lower(info, sym, symbols, majorVersion); 154 } 155 lower( SourceModuleInfo module, CompoundEnv<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> symbols, int majorVersion)156 private static byte[] lower( 157 SourceModuleInfo module, 158 CompoundEnv<ClassSymbol, TypeBoundClass> env, 159 Set<ClassSymbol> symbols, 160 int majorVersion) { 161 return new Lower(env).lower(module, symbols, majorVersion); 162 } 163 164 private final LowerSignature sig = new LowerSignature(); 165 private final Env<ClassSymbol, TypeBoundClass> env; 166 Lower(Env<ClassSymbol, TypeBoundClass> env)167 public Lower(Env<ClassSymbol, TypeBoundClass> env) { 168 this.env = env; 169 } 170 lower(SourceModuleInfo module, Set<ClassSymbol> symbols, int majorVersion)171 private byte[] lower(SourceModuleInfo module, Set<ClassSymbol> symbols, int majorVersion) { 172 String name = "module-info"; 173 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(module.annos()); 174 ClassFile.ModuleInfo moduleInfo = lowerModule(module); 175 176 ImmutableList.Builder<ClassFile.InnerClass> innerClasses = ImmutableList.builder(); 177 { 178 Set<ClassSymbol> all = new LinkedHashSet<>(); 179 for (ClassSymbol sym : sig.classes) { 180 addEnclosing(module.source(), env, all, sym); 181 } 182 for (ClassSymbol innerSym : all) { 183 innerClasses.add(innerClass(env, innerSym)); 184 } 185 } 186 187 ClassFile classfile = 188 new ClassFile( 189 /* access= */ TurbineFlag.ACC_MODULE, 190 majorVersion, 191 name, 192 /* signature= */ null, 193 /* superClass= */ null, 194 /* interfaces= */ ImmutableList.of(), 195 /* permits= */ ImmutableList.of(), 196 /* methods= */ ImmutableList.of(), 197 /* fields= */ ImmutableList.of(), 198 annotations, 199 innerClasses.build(), 200 /* typeAnnotations= */ ImmutableList.of(), 201 moduleInfo, 202 /* nestHost= */ null, 203 /* nestMembers= */ ImmutableList.of(), 204 /* record= */ null, 205 /* transitiveJar= */ null); 206 symbols.addAll(sig.classes); 207 return ClassWriter.writeClass(classfile); 208 } 209 lowerModule(SourceModuleInfo module)210 private ClassFile.ModuleInfo lowerModule(SourceModuleInfo module) { 211 ImmutableList.Builder<ClassFile.ModuleInfo.RequireInfo> requires = ImmutableList.builder(); 212 for (RequireInfo require : module.requires()) { 213 requires.add( 214 new ClassFile.ModuleInfo.RequireInfo( 215 require.moduleName(), require.flags(), require.version())); 216 } 217 ImmutableList.Builder<ClassFile.ModuleInfo.ExportInfo> exports = ImmutableList.builder(); 218 for (ExportInfo export : module.exports()) { 219 int exportAccess = 0; // not synthetic or mandated 220 exports.add( 221 new ClassFile.ModuleInfo.ExportInfo( 222 export.packageName(), exportAccess, export.modules())); 223 } 224 ImmutableList.Builder<ClassFile.ModuleInfo.OpenInfo> opens = ImmutableList.builder(); 225 for (OpenInfo open : module.opens()) { 226 int openAccess = 0; // not synthetic or mandated 227 opens.add(new ClassFile.ModuleInfo.OpenInfo(open.packageName(), openAccess, open.modules())); 228 } 229 ImmutableList.Builder<ClassFile.ModuleInfo.UseInfo> uses = ImmutableList.builder(); 230 for (UseInfo use : module.uses()) { 231 uses.add(new ClassFile.ModuleInfo.UseInfo(sig.descriptor(use.sym()))); 232 } 233 ImmutableList.Builder<ClassFile.ModuleInfo.ProvideInfo> provides = ImmutableList.builder(); 234 for (ProvideInfo provide : module.provides()) { 235 ImmutableList.Builder<String> impls = ImmutableList.builder(); 236 for (ClassSymbol impl : provide.impls()) { 237 impls.add(sig.descriptor(impl)); 238 } 239 provides.add( 240 new ClassFile.ModuleInfo.ProvideInfo(sig.descriptor(provide.sym()), impls.build())); 241 } 242 return new ClassFile.ModuleInfo( 243 module.name(), 244 module.flags(), 245 module.version(), 246 requires.build(), 247 exports.build(), 248 opens.build(), 249 uses.build(), 250 provides.build()); 251 } 252 lower( SourceTypeBoundClass info, ClassSymbol sym, Set<ClassSymbol> symbols, int majorVersion)253 private byte[] lower( 254 SourceTypeBoundClass info, ClassSymbol sym, Set<ClassSymbol> symbols, int majorVersion) { 255 int access = classAccess(info); 256 String name = sig.descriptor(sym); 257 String signature = sig.classSignature(info, env); 258 String superName = info.superclass() != null ? sig.descriptor(info.superclass()) : null; 259 List<String> interfaces = new ArrayList<>(); 260 for (ClassSymbol i : info.interfaces()) { 261 interfaces.add(sig.descriptor(i)); 262 } 263 List<String> permits = new ArrayList<>(); 264 for (ClassSymbol i : info.permits()) { 265 permits.add(sig.descriptor(i)); 266 } 267 268 ClassFile.RecordInfo record = null; 269 if (info.kind().equals(TurbineTyKind.RECORD)) { 270 ImmutableList.Builder<ClassFile.RecordInfo.RecordComponentInfo> components = 271 ImmutableList.builder(); 272 for (RecordComponentInfo component : info.components()) { 273 components.add(lowerComponent(info, component)); 274 } 275 record = new ClassFile.RecordInfo(components.build()); 276 } 277 278 List<ClassFile.MethodInfo> methods = new ArrayList<>(); 279 for (MethodInfo m : info.methods()) { 280 if (TurbineVisibility.fromAccess(m.access()) == TurbineVisibility.PRIVATE) { 281 // TODO(cushon): drop private members earlier? 282 continue; 283 } 284 methods.add(lowerMethod(m, sym)); 285 } 286 287 ImmutableList.Builder<ClassFile.FieldInfo> fields = ImmutableList.builder(); 288 for (FieldInfo f : info.fields()) { 289 if ((f.access() & TurbineFlag.ACC_PRIVATE) == TurbineFlag.ACC_PRIVATE) { 290 // TODO(cushon): drop private members earlier? 291 continue; 292 } 293 fields.add(lowerField(f)); 294 } 295 296 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(info.annotations()); 297 298 ImmutableList<TypeAnnotationInfo> typeAnnotations = classTypeAnnotations(info); 299 300 String nestHost = null; 301 ImmutableList<String> nestMembers = ImmutableList.of(); 302 // nests were added in Java 11, i.e. major version 55 303 if (majorVersion >= 55) { 304 nestHost = collectNestHost(info.source(), info.owner()); 305 nestMembers = nestHost == null ? collectNestMembers(info.source(), info) : ImmutableList.of(); 306 } 307 308 ImmutableList<ClassFile.InnerClass> inners = collectInnerClasses(info.source(), sym, info); 309 310 ClassFile classfile = 311 new ClassFile( 312 access, 313 majorVersion, 314 name, 315 signature, 316 superName, 317 interfaces, 318 permits, 319 methods, 320 fields.build(), 321 annotations, 322 inners, 323 typeAnnotations, 324 /* module= */ null, 325 nestHost, 326 nestMembers, 327 record, 328 /* transitiveJar= */ null); 329 330 symbols.addAll(sig.classes); 331 332 return ClassWriter.writeClass(classfile); 333 } 334 lowerComponent( SourceTypeBoundClass info, RecordComponentInfo c)335 private ClassFile.RecordInfo.RecordComponentInfo lowerComponent( 336 SourceTypeBoundClass info, RecordComponentInfo c) { 337 Function<TyVarSymbol, TyVarInfo> tenv = new TyVarEnv(info.typeParameterTypes()); 338 String desc = SigWriter.type(sig.signature(Erasure.erase(c.type(), tenv))); 339 String signature = sig.fieldSignature(c.type()); 340 ImmutableList.Builder<TypeAnnotationInfo> typeAnnotations = ImmutableList.builder(); 341 lowerTypeAnnotations( 342 typeAnnotations, c.type(), TargetType.FIELD, TypeAnnotationInfo.EMPTY_TARGET); 343 return new ClassFile.RecordInfo.RecordComponentInfo( 344 c.name(), desc, signature, lowerAnnotations(c.annotations()), typeAnnotations.build()); 345 } 346 lowerMethod(final MethodInfo m, final ClassSymbol sym)347 private ClassFile.MethodInfo lowerMethod(final MethodInfo m, final ClassSymbol sym) { 348 int access = m.access(); 349 Function<TyVarSymbol, TyVarInfo> tenv = new TyVarEnv(m.tyParams()); 350 String name = m.name(); 351 String desc = methodDescriptor(m, tenv); 352 String signature = sig.methodSignature(env, m, sym); 353 ImmutableList.Builder<String> exceptions = ImmutableList.builder(); 354 if (!m.exceptions().isEmpty()) { 355 for (Type e : m.exceptions()) { 356 exceptions.add(sig.descriptor(((ClassTy) Erasure.erase(e, tenv)).sym())); 357 } 358 } 359 360 ElementValue defaultValue = m.defaultValue() != null ? annotationValue(m.defaultValue()) : null; 361 362 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(m.annotations()); 363 364 ImmutableList<ImmutableList<AnnotationInfo>> paramAnnotations = parameterAnnotations(m); 365 366 ImmutableList<TypeAnnotationInfo> typeAnnotations = methodTypeAnnotations(m); 367 368 ImmutableList<ClassFile.MethodInfo.ParameterInfo> parameters = methodParameters(m); 369 370 return new ClassFile.MethodInfo( 371 access, 372 name, 373 desc, 374 signature, 375 exceptions.build(), 376 defaultValue, 377 annotations, 378 paramAnnotations, 379 typeAnnotations, 380 parameters); 381 } 382 methodParameters(MethodInfo m)383 private ImmutableList<ParameterInfo> methodParameters(MethodInfo m) { 384 ImmutableList.Builder<ParameterInfo> result = ImmutableList.builder(); 385 for (ParamInfo p : m.parameters()) { 386 result.add(new ParameterInfo(p.name(), p.access() & PARAMETER_ACCESS_MASK)); 387 } 388 return result.build(); 389 } 390 391 private static final int PARAMETER_ACCESS_MASK = 392 TurbineFlag.ACC_MANDATED | TurbineFlag.ACC_FINAL | TurbineFlag.ACC_SYNTHETIC; 393 parameterAnnotations(MethodInfo m)394 private ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations(MethodInfo m) { 395 ImmutableList.Builder<ImmutableList<AnnotationInfo>> annotations = ImmutableList.builder(); 396 for (ParamInfo parameter : m.parameters()) { 397 if (parameter.synthetic()) { 398 continue; 399 } 400 if (parameter.annotations().isEmpty()) { 401 annotations.add(ImmutableList.of()); 402 continue; 403 } 404 ImmutableList.Builder<AnnotationInfo> parameterAnnotations = ImmutableList.builder(); 405 for (AnnoInfo annotation : parameter.annotations()) { 406 Boolean visible = isVisible(annotation.sym()); 407 if (visible == null) { 408 continue; 409 } 410 String desc = sig.objectType(annotation.sym()); 411 parameterAnnotations.add( 412 new AnnotationInfo(desc, visible, annotationValues(annotation.values()))); 413 } 414 annotations.add(parameterAnnotations.build()); 415 } 416 return annotations.build(); 417 } 418 methodDescriptor(MethodInfo m, Function<TyVarSymbol, TyVarInfo> tenv)419 private String methodDescriptor(MethodInfo m, Function<TyVarSymbol, TyVarInfo> tenv) { 420 ImmutableList<Sig.TyParamSig> typarams = ImmutableList.of(); 421 ImmutableList.Builder<TySig> fparams = ImmutableList.builder(); 422 for (ParamInfo t : m.parameters()) { 423 fparams.add(sig.signature(Erasure.erase(t.type(), tenv))); 424 } 425 TySig result = sig.signature(Erasure.erase(m.returnType(), tenv)); 426 ImmutableList<TySig> excns = ImmutableList.of(); 427 return SigWriter.method(new MethodSig(typarams, fparams.build(), result, excns)); 428 } 429 lowerField(FieldInfo f)430 private ClassFile.FieldInfo lowerField(FieldInfo f) { 431 final String name = f.name(); 432 Function<TyVarSymbol, TyVarInfo> tenv = new TyVarEnv(ImmutableMap.of()); 433 String desc = SigWriter.type(sig.signature(Erasure.erase(f.type(), tenv))); 434 String signature = sig.fieldSignature(f.type()); 435 436 ImmutableList<AnnotationInfo> annotations = lowerAnnotations(f.annotations()); 437 438 ImmutableList.Builder<TypeAnnotationInfo> typeAnnotations = ImmutableList.builder(); 439 lowerTypeAnnotations( 440 typeAnnotations, f.type(), TargetType.FIELD, TypeAnnotationInfo.EMPTY_TARGET); 441 442 return new ClassFile.FieldInfo( 443 f.access(), name, desc, signature, f.value(), annotations, typeAnnotations.build()); 444 } 445 446 /** Creates inner class attributes for all referenced inner classes. */ collectInnerClasses( SourceFile source, ClassSymbol origin, SourceTypeBoundClass info)447 private ImmutableList<ClassFile.InnerClass> collectInnerClasses( 448 SourceFile source, ClassSymbol origin, SourceTypeBoundClass info) { 449 Set<ClassSymbol> all = new LinkedHashSet<>(); 450 addEnclosing(source, env, all, origin); 451 for (ClassSymbol sym : info.children().values()) { 452 addEnclosing(source, env, all, sym); 453 } 454 for (ClassSymbol sym : sig.classes) { 455 addEnclosing(source, env, all, sym); 456 } 457 ImmutableList.Builder<ClassFile.InnerClass> inners = ImmutableList.builder(); 458 for (ClassSymbol innerSym : all) { 459 inners.add(innerClass(env, innerSym)); 460 } 461 return inners.build(); 462 } 463 464 /** 465 * Record all enclosing declarations of a symbol, to make sure the necessary InnerClass attributes 466 * are added. 467 * 468 * <p>javac expects InnerClass attributes for enclosing classes to appear before their member 469 * classes' entries. 470 */ addEnclosing( SourceFile source, Env<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> all, ClassSymbol sym)471 private void addEnclosing( 472 SourceFile source, 473 Env<ClassSymbol, TypeBoundClass> env, 474 Set<ClassSymbol> all, 475 ClassSymbol sym) { 476 TypeBoundClass info = env.get(sym); 477 if (info == null) { 478 throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, sym); 479 } 480 ClassSymbol owner = info.owner(); 481 if (owner != null) { 482 addEnclosing(source, env, all, owner); 483 all.add(sym); 484 } 485 } 486 collectNestHost(SourceFile source, @Nullable ClassSymbol sym)487 private @Nullable String collectNestHost(SourceFile source, @Nullable ClassSymbol sym) { 488 if (sym == null) { 489 return null; 490 } 491 while (true) { 492 TypeBoundClass info = env.get(sym); 493 if (info == null) { 494 throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, sym); 495 } 496 if (info.owner() == null) { 497 return sig.descriptor(sym); 498 } 499 sym = info.owner(); 500 } 501 } 502 collectNestMembers(SourceFile source, SourceTypeBoundClass info)503 private ImmutableList<String> collectNestMembers(SourceFile source, SourceTypeBoundClass info) { 504 Set<ClassSymbol> nestMembers = new LinkedHashSet<>(); 505 for (ClassSymbol child : info.children().values()) { 506 addNestMembers(source, env, nestMembers, child); 507 } 508 ImmutableList.Builder<String> result = ImmutableList.builder(); 509 for (ClassSymbol nestMember : nestMembers) { 510 result.add(sig.descriptor(nestMember)); 511 } 512 return result.build(); 513 } 514 addNestMembers( SourceFile source, Env<ClassSymbol, TypeBoundClass> env, Set<ClassSymbol> nestMembers, ClassSymbol sym)515 private static void addNestMembers( 516 SourceFile source, 517 Env<ClassSymbol, TypeBoundClass> env, 518 Set<ClassSymbol> nestMembers, 519 ClassSymbol sym) { 520 if (!nestMembers.add(sym)) { 521 return; 522 } 523 TypeBoundClass info = env.get(sym); 524 if (info == null) { 525 throw TurbineError.format(source, ErrorKind.CLASS_FILE_NOT_FOUND, sym); 526 } 527 for (ClassSymbol child : info.children().values()) { 528 addNestMembers(source, env, nestMembers, child); 529 } 530 } 531 532 /** 533 * Creates an inner class attribute, given an inner class that was referenced somewhere in the 534 * class. 535 */ innerClass( Env<ClassSymbol, TypeBoundClass> env, ClassSymbol innerSym)536 private ClassFile.InnerClass innerClass( 537 Env<ClassSymbol, TypeBoundClass> env, ClassSymbol innerSym) { 538 TypeBoundClass inner = env.getNonNull(innerSym); 539 // this inner class is known to have an owner 540 ClassSymbol owner = requireNonNull(inner.owner()); 541 542 String innerName = innerSym.binaryName().substring(owner.binaryName().length() + 1); 543 544 int access = inner.access(); 545 access &= ~(TurbineFlag.ACC_SUPER | TurbineFlag.ACC_STRICT); 546 547 return new ClassFile.InnerClass(innerSym.binaryName(), owner.binaryName(), innerName, access); 548 } 549 550 /** Updates visibility, and unsets access bits that can only be set in InnerClass. */ classAccess(SourceTypeBoundClass info)551 private int classAccess(SourceTypeBoundClass info) { 552 int access = info.access(); 553 access &= ~(TurbineFlag.ACC_STATIC | TurbineFlag.ACC_PRIVATE | TurbineFlag.ACC_STRICT); 554 if ((access & TurbineFlag.ACC_PROTECTED) != 0) { 555 access &= ~TurbineFlag.ACC_PROTECTED; 556 access |= TurbineFlag.ACC_PUBLIC; 557 } 558 return access; 559 } 560 561 /** 562 * Looks up {@link TyVarInfo}s. 563 * 564 * <p>We could generalize {@link com.google.turbine.binder.lookup.Scope} instead, but this isn't 565 * needed anywhere else. 566 */ 567 class TyVarEnv implements Function<TyVarSymbol, TyVarInfo> { 568 569 private final Map<TyVarSymbol, TyVarInfo> tyParams; 570 571 /** @param tyParams the initial lookup scope, e.g. a method's formal type parameters. */ TyVarEnv(Map<TyVarSymbol, TyVarInfo> tyParams)572 public TyVarEnv(Map<TyVarSymbol, TyVarInfo> tyParams) { 573 this.tyParams = tyParams; 574 } 575 576 @Override apply(TyVarSymbol sym)577 public TyVarInfo apply(TyVarSymbol sym) { 578 TyVarInfo result = tyParams.get(sym); 579 if (result != null) { 580 return result; 581 } 582 // type variables can only be declared by methods and classes, 583 // and we've already handled methods 584 Symbol ownerSym = sym.owner(); 585 if (ownerSym.symKind() != Symbol.Kind.CLASS) { 586 throw new AssertionError(sym); 587 } 588 // anything that lexically encloses the class being lowered 589 // must be in the same compilation unit, so we have source 590 // information for it 591 TypeBoundClass owner = env.getNonNull((ClassSymbol) ownerSym); 592 return owner.typeParameterTypes().get(sym); 593 } 594 } 595 lowerAnnotations(ImmutableList<AnnoInfo> annotations)596 private ImmutableList<AnnotationInfo> lowerAnnotations(ImmutableList<AnnoInfo> annotations) { 597 ImmutableList.Builder<AnnotationInfo> lowered = ImmutableList.builder(); 598 for (AnnoInfo annotation : annotations) { 599 AnnotationInfo anno = lowerAnnotation(annotation); 600 if (anno == null) { 601 continue; 602 } 603 lowered.add(anno); 604 } 605 return lowered.build(); 606 } 607 lowerAnnotation(AnnoInfo annotation)608 private @Nullable AnnotationInfo lowerAnnotation(AnnoInfo annotation) { 609 Boolean visible = isVisible(annotation.sym()); 610 if (visible == null) { 611 return null; 612 } 613 return new AnnotationInfo( 614 sig.objectType(annotation.sym()), visible, annotationValues(annotation.values())); 615 } 616 617 /** 618 * Returns true if the annotation is visible at runtime, false if it is not visible at runtime, 619 * and {@code null} if it should not be retained in bytecode. 620 */ isVisible(ClassSymbol sym)621 private @Nullable Boolean isVisible(ClassSymbol sym) { 622 RetentionPolicy retention = 623 requireNonNull(env.getNonNull(sym).annotationMetadata()).retention(); 624 switch (retention) { 625 case CLASS: 626 return false; 627 case RUNTIME: 628 return true; 629 case SOURCE: 630 return null; 631 } 632 throw new AssertionError(retention); 633 } 634 annotationValues(ImmutableMap<String, Const> values)635 private ImmutableMap<String, ElementValue> annotationValues(ImmutableMap<String, Const> values) { 636 ImmutableMap.Builder<String, ElementValue> result = ImmutableMap.builder(); 637 for (Map.Entry<String, Const> entry : values.entrySet()) { 638 result.put(entry.getKey(), annotationValue(entry.getValue())); 639 } 640 return result.buildOrThrow(); 641 } 642 annotationValue(Const value)643 private ElementValue annotationValue(Const value) { 644 switch (value.kind()) { 645 case CLASS_LITERAL: 646 { 647 TurbineClassValue classValue = (TurbineClassValue) value; 648 return new ElementValue.ConstTurbineClassValue( 649 SigWriter.type(sig.signature(classValue.type()))); 650 } 651 case ENUM_CONSTANT: 652 { 653 EnumConstantValue enumValue = (EnumConstantValue) value; 654 return new ElementValue.EnumConstValue( 655 sig.objectType(enumValue.sym().owner()), enumValue.sym().name()); 656 } 657 case ARRAY: 658 { 659 Const.ArrayInitValue arrayValue = (Const.ArrayInitValue) value; 660 List<ElementValue> values = new ArrayList<>(); 661 for (Const element : arrayValue.elements()) { 662 values.add(annotationValue(element)); 663 } 664 return new ElementValue.ArrayValue(values); 665 } 666 case ANNOTATION: 667 { 668 TurbineAnnotationValue annotationValue = (TurbineAnnotationValue) value; 669 Boolean visible = isVisible(annotationValue.sym()); 670 if (visible == null) { 671 visible = true; 672 } 673 return new ElementValue.ConstTurbineAnnotationValue( 674 new AnnotationInfo( 675 sig.objectType(annotationValue.sym()), 676 visible, 677 annotationValues(annotationValue.values()))); 678 } 679 case PRIMITIVE: 680 return new ElementValue.ConstValue((Const.Value) value); 681 } 682 throw new AssertionError(value.kind()); 683 } 684 685 /** Lower type annotations in a class declaration's signature. */ classTypeAnnotations(SourceTypeBoundClass info)686 private ImmutableList<TypeAnnotationInfo> classTypeAnnotations(SourceTypeBoundClass info) { 687 ImmutableList.Builder<TypeAnnotationInfo> result = ImmutableList.builder(); 688 { 689 if (info.superClassType() != null) { 690 lowerTypeAnnotations( 691 result, 692 info.superClassType(), 693 TargetType.SUPERTYPE, 694 new TypeAnnotationInfo.SuperTypeTarget(-1)); 695 } 696 int idx = 0; 697 for (Type i : info.interfaceTypes()) { 698 lowerTypeAnnotations( 699 result, i, TargetType.SUPERTYPE, new TypeAnnotationInfo.SuperTypeTarget(idx++)); 700 } 701 } 702 typeParameterAnnotations( 703 result, 704 info.typeParameterTypes().values(), 705 TargetType.CLASS_TYPE_PARAMETER, 706 TargetType.CLASS_TYPE_PARAMETER_BOUND); 707 return result.build(); 708 } 709 710 /** Lower type annotations in a method declaration's signature. */ methodTypeAnnotations(MethodInfo m)711 private ImmutableList<TypeAnnotationInfo> methodTypeAnnotations(MethodInfo m) { 712 ImmutableList.Builder<TypeAnnotationInfo> result = ImmutableList.builder(); 713 714 typeParameterAnnotations( 715 result, 716 m.tyParams().values(), 717 TargetType.METHOD_TYPE_PARAMETER, 718 TargetType.METHOD_TYPE_PARAMETER_BOUND); 719 720 { 721 int idx = 0; 722 for (Type e : m.exceptions()) { 723 lowerTypeAnnotations(result, e, TargetType.METHOD_THROWS, new ThrowsTarget(idx++)); 724 } 725 } 726 727 if (m.receiver() != null) { 728 lowerTypeAnnotations( 729 result, 730 m.receiver().type(), 731 TargetType.METHOD_RECEIVER_PARAMETER, 732 TypeAnnotationInfo.EMPTY_TARGET); 733 } 734 735 lowerTypeAnnotations( 736 result, m.returnType(), TargetType.METHOD_RETURN, TypeAnnotationInfo.EMPTY_TARGET); 737 738 { 739 int idx = 0; 740 for (ParamInfo p : m.parameters()) { 741 if (p.synthetic()) { 742 continue; 743 } 744 lowerTypeAnnotations( 745 result, 746 p.type(), 747 TargetType.METHOD_FORMAL_PARAMETER, 748 new TypeAnnotationInfo.FormalParameterTarget(idx++)); 749 } 750 } 751 752 return result.build(); 753 } 754 755 /** 756 * Lower type annotations on class or method type parameters, either on the parameters themselves 757 * or on bounds. 758 */ typeParameterAnnotations( ImmutableList.Builder<TypeAnnotationInfo> result, Iterable<TyVarInfo> typeParameters, TargetType targetType, TargetType boundTargetType)759 private void typeParameterAnnotations( 760 ImmutableList.Builder<TypeAnnotationInfo> result, 761 Iterable<TyVarInfo> typeParameters, 762 TargetType targetType, 763 TargetType boundTargetType) { 764 int typeParameterIndex = 0; 765 for (TyVarInfo p : typeParameters) { 766 for (AnnoInfo anno : groupRepeated(env, p.annotations())) { 767 AnnotationInfo info = lowerAnnotation(anno); 768 if (info == null) { 769 continue; 770 } 771 result.add( 772 new TypeAnnotationInfo( 773 targetType, 774 new TypeAnnotationInfo.TypeParameterTarget(typeParameterIndex), 775 TypePath.root(), 776 info)); 777 } 778 int boundIndex = 0; 779 for (Type i : p.upperBound().bounds()) { 780 if (boundIndex == 0 && isInterface(i, env)) { 781 // super class bound index is always 0; interface bounds start at 1 782 boundIndex++; 783 } 784 lowerTypeAnnotations( 785 result, 786 i, 787 boundTargetType, 788 new TypeAnnotationInfo.TypeParameterBoundTarget(typeParameterIndex, boundIndex++)); 789 } 790 typeParameterIndex++; 791 } 792 } 793 isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env)794 private boolean isInterface(Type type, Env<ClassSymbol, TypeBoundClass> env) { 795 return type.tyKind() == TyKind.CLASS_TY 796 && env.getNonNull(((ClassTy) type).sym()).kind() == TurbineTyKind.INTERFACE; 797 } 798 lowerTypeAnnotations( ImmutableList.Builder<TypeAnnotationInfo> result, Type type, TargetType targetType, Target target)799 private void lowerTypeAnnotations( 800 ImmutableList.Builder<TypeAnnotationInfo> result, 801 Type type, 802 TargetType targetType, 803 Target target) { 804 new LowerTypeAnnotations(result, targetType, target) 805 .lowerTypeAnnotations(type, TypePath.root()); 806 } 807 808 class LowerTypeAnnotations { 809 private final ImmutableList.Builder<TypeAnnotationInfo> result; 810 private final TargetType targetType; 811 private final Target target; 812 LowerTypeAnnotations( ImmutableList.Builder<TypeAnnotationInfo> result, TargetType targetType, Target target)813 public LowerTypeAnnotations( 814 ImmutableList.Builder<TypeAnnotationInfo> result, TargetType targetType, Target target) { 815 this.result = result; 816 this.targetType = targetType; 817 this.target = target; 818 } 819 820 /** 821 * Lower all type annotations present in a type. 822 * 823 * <p>Recursively descends into nested types, and accumulates a type path structure to locate 824 * the annotation in the signature. 825 */ lowerTypeAnnotations(Type type, TypePath path)826 private void lowerTypeAnnotations(Type type, TypePath path) { 827 switch (type.tyKind()) { 828 case TY_VAR: 829 lowerTypeAnnotations(((TyVar) type).annos(), path); 830 break; 831 case CLASS_TY: 832 lowerClassTypeTypeAnnotations((ClassTy) type, path); 833 break; 834 case ARRAY_TY: 835 lowerArrayTypeAnnotations(type, path); 836 break; 837 case WILD_TY: 838 lowerWildTyTypeAnnotations((WildTy) type, path); 839 break; 840 case PRIM_TY: 841 lowerTypeAnnotations(((Type.PrimTy) type).annos(), path); 842 break; 843 case VOID_TY: 844 break; 845 default: 846 throw new AssertionError(type.tyKind()); 847 } 848 } 849 850 /** Lower a list of type annotations. */ lowerTypeAnnotations(ImmutableList<AnnoInfo> annos, TypePath path)851 private void lowerTypeAnnotations(ImmutableList<AnnoInfo> annos, TypePath path) { 852 for (AnnoInfo anno : groupRepeated(env, annos)) { 853 AnnotationInfo info = lowerAnnotation(anno); 854 if (info == null) { 855 continue; 856 } 857 result.add(new TypeAnnotationInfo(targetType, target, path, info)); 858 } 859 } 860 lowerWildTyTypeAnnotations(WildTy type, TypePath path)861 private void lowerWildTyTypeAnnotations(WildTy type, TypePath path) { 862 switch (type.boundKind()) { 863 case NONE: 864 lowerTypeAnnotations(type.annotations(), path); 865 break; 866 case UPPER: 867 case LOWER: 868 lowerTypeAnnotations(type.annotations(), path); 869 lowerTypeAnnotations(type.bound(), path.wild()); 870 break; 871 } 872 } 873 lowerArrayTypeAnnotations(Type type, TypePath path)874 private void lowerArrayTypeAnnotations(Type type, TypePath path) { 875 Type base = type; 876 Deque<ArrayTy> flat = new ArrayDeque<>(); 877 while (base instanceof ArrayTy) { 878 ArrayTy arrayTy = (ArrayTy) base; 879 flat.addFirst(arrayTy); 880 base = arrayTy.elementType(); 881 } 882 for (ArrayTy arrayTy : flat) { 883 lowerTypeAnnotations(arrayTy.annos(), path); 884 path = path.array(); 885 } 886 lowerTypeAnnotations(base, path); 887 } 888 lowerClassTypeTypeAnnotations(ClassTy type, TypePath path)889 private void lowerClassTypeTypeAnnotations(ClassTy type, TypePath path) { 890 for (SimpleClassTy simple : type.classes()) { 891 lowerTypeAnnotations(simple.annos(), path); 892 int idx = 0; 893 for (Type a : simple.targs()) { 894 lowerTypeAnnotations(a, path.typeArgument(idx++)); 895 } 896 path = path.nested(); 897 } 898 } 899 } 900 } 901