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