Home | History | Annotate | Download | only in bytecode
      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.bytecode;
     18 
     19 import static java.util.Objects.requireNonNull;
     20 
     21 import com.google.common.collect.ImmutableList;
     22 import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
     23 import com.google.turbine.model.Const;
     24 import com.google.turbine.model.Const.Value;
     25 import java.util.ArrayDeque;
     26 import java.util.Deque;
     27 import java.util.List;
     28 import java.util.Map;
     29 import javax.annotation.Nullable;
     30 
     31 /** A JVMS 4.1 ClassFile. */
     32 public class ClassFile {
     33 
     34   private final int access;
     35   private final String name;
     36   private final String signature;
     37   private final String superClass;
     38   private final List<String> interfaces;
     39   private final List<MethodInfo> methods;
     40   private final List<FieldInfo> fields;
     41   private final List<AnnotationInfo> annotations;
     42   private final List<InnerClass> innerClasses;
     43   private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
     44 
     45   public ClassFile(
     46       int access,
     47       String name,
     48       String signature,
     49       String superClass,
     50       List<String> interfaces,
     51       List<MethodInfo> methods,
     52       List<FieldInfo> fields,
     53       List<AnnotationInfo> annotations,
     54       List<InnerClass> innerClasses,
     55       ImmutableList<TypeAnnotationInfo> typeAnnotations) {
     56     this.access = access;
     57     this.name = name;
     58     this.signature = signature;
     59     this.superClass = superClass;
     60     this.interfaces = interfaces;
     61     this.methods = methods;
     62     this.fields = fields;
     63     this.annotations = annotations;
     64     this.innerClasses = innerClasses;
     65     this.typeAnnotations = typeAnnotations;
     66   }
     67 
     68   /** Class access and property flags. */
     69   public int access() {
     70     return access;
     71   }
     72 
     73   /** The name of the class or interface. */
     74   public String name() {
     75     return name;
     76   }
     77 
     78   /** The value of the Signature attribute. */
     79   public String signature() {
     80     return signature;
     81   }
     82 
     83   /** The super class. */
     84   public String superName() {
     85     return superClass;
     86   }
     87 
     88   /** The direct superinterfaces. */
     89   public List<String> interfaces() {
     90     return interfaces;
     91   }
     92 
     93   /** Methods declared by this class or interfaces type. */
     94   public List<MethodInfo> methods() {
     95     return methods;
     96   }
     97 
     98   /** Fields declared by this class or interfaces type. */
     99   public List<FieldInfo> fields() {
    100     return fields;
    101   }
    102 
    103   /** Declaration annotations of the class. */
    104   public List<AnnotationInfo> annotations() {
    105     return annotations;
    106   }
    107 
    108   /** Inner class information. */
    109   public List<InnerClass> innerClasses() {
    110     return innerClasses;
    111   }
    112 
    113   /** Type annotations. */
    114   public ImmutableList<TypeAnnotationInfo> typeAnnotations() {
    115     return typeAnnotations;
    116   }
    117 
    118   /** The contents of a JVMS 4.5 field_info structure. */
    119   public static class FieldInfo {
    120 
    121     private final int access;
    122     private final String name;
    123     private final String descriptor;
    124     @Nullable private final String signature;
    125     @Nullable private final Const.Value value;
    126     private final List<AnnotationInfo> annotations;
    127     private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
    128 
    129     public FieldInfo(
    130         int access,
    131         String name,
    132         String descriptor,
    133         @Nullable String signature,
    134         Value value,
    135         List<AnnotationInfo> annotations,
    136         ImmutableList<TypeAnnotationInfo> typeAnnotations) {
    137       this.access = access;
    138       this.name = name;
    139       this.descriptor = descriptor;
    140       this.signature = signature;
    141       this.value = value;
    142       this.annotations = annotations;
    143       this.typeAnnotations = typeAnnotations;
    144     }
    145 
    146     /** Field access and property flags. */
    147     public int access() {
    148       return access;
    149     }
    150 
    151     /** The name of the field. */
    152     public String name() {
    153       return name;
    154     }
    155 
    156     /** The descriptor. */
    157     public String descriptor() {
    158       return descriptor;
    159     }
    160 
    161     /** The value of Signature attribute. */
    162     @Nullable
    163     public String signature() {
    164       return signature;
    165     }
    166 
    167     /** The compile-time constant value. */
    168     @Nullable
    169     public Const.Value value() {
    170       return value;
    171     }
    172 
    173     /** Declaration annotations of the field. */
    174     public List<AnnotationInfo> annotations() {
    175       return annotations;
    176     }
    177 
    178     /** Type annotations. */
    179     public ImmutableList<TypeAnnotationInfo> typeAnnotations() {
    180       return typeAnnotations;
    181     }
    182   }
    183 
    184   /** A JVMS 4.7.6 InnerClasses attribute. */
    185   public static class InnerClass {
    186 
    187     private final String innerClass;
    188     private final String outerClass;
    189     private final String innerName;
    190     private final int access;
    191 
    192     public InnerClass(String innerClass, String outerClass, String innerName, int access) {
    193       this.innerClass = requireNonNull(innerClass);
    194       this.outerClass = requireNonNull(outerClass);
    195       this.innerName = requireNonNull(innerName);
    196       this.access = access;
    197     }
    198 
    199     /** The binary name of the inner class. */
    200     public String innerClass() {
    201       return innerClass;
    202     }
    203 
    204     /** The binary name of the enclosing class. */
    205     public String outerClass() {
    206       return outerClass;
    207     }
    208 
    209     /** The simple name of the inner class. */
    210     public String innerName() {
    211       return innerName;
    212     }
    213 
    214     /** Access and property flags of the inner class; see JVMS table 4.8. */
    215     public int access() {
    216       return access;
    217     }
    218   }
    219 
    220   /** The contents of a JVMS 4.6 method_info structure. */
    221   public static class MethodInfo {
    222 
    223     private final int access;
    224     private final String name;
    225     private final String descriptor;
    226     @Nullable private final String signature;
    227     private final List<String> exceptions;
    228     @Nullable private final AnnotationInfo.ElementValue defaultValue;
    229     private final List<AnnotationInfo> annotations;
    230     private final ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations;
    231     private final ImmutableList<TypeAnnotationInfo> typeAnnotations;
    232     private final ImmutableList<ParameterInfo> parameters;
    233 
    234     public MethodInfo(
    235         int access,
    236         String name,
    237         String descriptor,
    238         @Nullable String signature,
    239         List<String> exceptions,
    240         @Nullable ElementValue defaultValue,
    241         List<AnnotationInfo> annotations,
    242         ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations,
    243         ImmutableList<TypeAnnotationInfo> typeAnnotations,
    244         ImmutableList<ParameterInfo> parameters) {
    245       this.access = access;
    246       this.name = name;
    247       this.descriptor = descriptor;
    248       this.signature = signature;
    249       this.exceptions = exceptions;
    250       this.defaultValue = defaultValue;
    251       this.annotations = annotations;
    252       this.parameterAnnotations = parameterAnnotations;
    253       this.typeAnnotations = typeAnnotations;
    254       this.parameters = parameters;
    255     }
    256 
    257     /** Method access and property flags. */
    258     public int access() {
    259       return access;
    260     }
    261 
    262     /** The name of the method. */
    263     public String name() {
    264       return name;
    265     }
    266 
    267     /** The descriptor. */
    268     public String descriptor() {
    269       return descriptor;
    270     }
    271 
    272     /** The value of Signature attribute. */
    273     @Nullable
    274     public String signature() {
    275       return signature;
    276     }
    277 
    278     /** The value of Exceptions attribute. */
    279     public List<String> exceptions() {
    280       return exceptions;
    281     }
    282 
    283     /** The value of the AnnotationDefault attribute. */
    284     @Nullable
    285     public AnnotationInfo.ElementValue defaultValue() {
    286       return defaultValue;
    287     }
    288 
    289     /** Declaration annotations of the method. */
    290     public List<AnnotationInfo> annotations() {
    291       return annotations;
    292     }
    293 
    294     /** Declaration annotations of the formal parameters. */
    295     public ImmutableList<ImmutableList<AnnotationInfo>> parameterAnnotations() {
    296       return parameterAnnotations;
    297     }
    298 
    299     /** Type annotations. */
    300     public ImmutableList<TypeAnnotationInfo> typeAnnotations() {
    301       return typeAnnotations;
    302     }
    303 
    304     /** Formal parameters. */
    305     public ImmutableList<ParameterInfo> parameters() {
    306       return parameters;
    307     }
    308 
    309     /** A formal parameter. */
    310     public static class ParameterInfo {
    311       private final String name;
    312       private final int access;
    313 
    314       public ParameterInfo(String name, int access) {
    315         this.name = name;
    316         this.access = access;
    317       }
    318 
    319       /** Returns the parameter's name. */
    320       public String name() {
    321         return name;
    322       }
    323 
    324       /** Returns the parameter's modifiers. */
    325       public int access() {
    326         return access;
    327       }
    328     }
    329   }
    330 
    331   /** The contents of a JVMS 4.7.16 annotation structure. */
    332   public static class AnnotationInfo {
    333 
    334     private final String typeName;
    335     private final boolean runtimeVisible;
    336     private final Map<String, ElementValue> elementValuePairs;
    337 
    338     public AnnotationInfo(
    339         String typeName, boolean runtimeVisible, Map<String, ElementValue> elementValuePairs) {
    340       this.typeName = typeName;
    341       this.runtimeVisible = runtimeVisible;
    342       this.elementValuePairs = elementValuePairs;
    343     }
    344 
    345     /** The JVMS 4.3.2 field descriptor for the type of the annotation. */
    346     public String typeName() {
    347       return typeName;
    348     }
    349 
    350     /** Returns true if the annotation is visible at runtime. */
    351     public boolean isRuntimeVisible() {
    352       return runtimeVisible;
    353     }
    354 
    355     /** The element-value pairs of the annotation. */
    356     public Map<String, ElementValue> elementValuePairs() {
    357       return elementValuePairs;
    358     }
    359 
    360     /** A value of a JVMS 4.7.16.1 element-value pair. */
    361     public interface ElementValue {
    362 
    363       /** The value kind. */
    364       Kind kind();
    365 
    366       /** Element value kinds. */
    367       enum Kind {
    368         ENUM,
    369         CONST,
    370         ARRAY,
    371         CLASS,
    372         ANNOTATION
    373       }
    374 
    375       /** An enum constant value. */
    376       class EnumConstValue implements ElementValue {
    377 
    378         private final String typeName;
    379         private final String constName;
    380 
    381         public EnumConstValue(String typeName, String constName) {
    382           this.typeName = typeName;
    383           this.constName = constName;
    384         }
    385 
    386         @Override
    387         public Kind kind() {
    388           return Kind.ENUM;
    389         }
    390 
    391         /** The type of the enum. */
    392         public String typeName() {
    393           return typeName;
    394         }
    395 
    396         /** The name of the enum constant. */
    397         public String constName() {
    398           return constName;
    399         }
    400       }
    401 
    402       /** A primitive or string constant value. */
    403       class ConstValue implements ElementValue {
    404 
    405         private final Const.Value value;
    406 
    407         public ConstValue(Const.Value value) {
    408 
    409           this.value = value;
    410         }
    411 
    412         @Override
    413         public Kind kind() {
    414           return Kind.CONST;
    415         }
    416 
    417         /** The constant value. */
    418         public Const.Value value() {
    419           return value;
    420         }
    421       }
    422 
    423       /** A constant array value. */
    424       class ArrayValue implements ElementValue {
    425 
    426         private final List<ElementValue> elements;
    427 
    428         public ArrayValue(List<ElementValue> elements) {
    429           this.elements = elements;
    430         }
    431 
    432         @Override
    433         public Kind kind() {
    434           return Kind.ARRAY;
    435         }
    436 
    437         /** The elements of the array. */
    438         public List<ElementValue> elements() {
    439           return elements;
    440         }
    441       }
    442 
    443       /** A constant class literal value. */
    444       class ConstClassValue implements ElementValue {
    445 
    446         private final String className;
    447 
    448         public ConstClassValue(String className) {
    449           this.className = className;
    450         }
    451 
    452         @Override
    453         public Kind kind() {
    454           return Kind.CLASS;
    455         }
    456 
    457         /** The class name. */
    458         public String className() {
    459           return className;
    460         }
    461       }
    462 
    463       /** A nested annotation value. */
    464       class AnnotationValue implements ElementValue {
    465 
    466         private final AnnotationInfo annotation;
    467 
    468         public AnnotationValue(AnnotationInfo annotation) {
    469           this.annotation = annotation;
    470         }
    471 
    472         @Override
    473         public Kind kind() {
    474           return Kind.ANNOTATION;
    475         }
    476 
    477         /** The annotation. */
    478         public AnnotationInfo annotation() {
    479           return annotation;
    480         }
    481       }
    482     }
    483   }
    484 
    485   /** The contents of a JVMS 4.7.20 type annotation structure. */
    486   public static class TypeAnnotationInfo {
    487     private final TargetType targetType;
    488     private final Target target;
    489     private final TypePath path;
    490     private final AnnotationInfo anno;
    491 
    492     public TypeAnnotationInfo(
    493         TargetType targetType, Target target, TypePath path, AnnotationInfo anno) {
    494       this.targetType = targetType;
    495       this.target = target;
    496       this.path = path;
    497       this.anno = anno;
    498     }
    499 
    500     /**
    501      * The underlying annotation info (type, visibility, element-value pairs); shared with
    502      * declaration annotations.
    503      */
    504     public AnnotationInfo anno() {
    505       return anno;
    506     }
    507 
    508     /** A JVMS 4.7.20 target_type kind, denotes the type context where the annotation appears. */
    509     public TargetType targetType() {
    510       return targetType;
    511     }
    512 
    513     /** A JVMS 4.7.20 target_info structure. */
    514     public Target target() {
    515       return target;
    516     }
    517 
    518     /**
    519      * A JVMS 4.7.20 type_path structure, denotes which part of the type the annotation applies to.
    520      */
    521     public TypePath path() {
    522       return path;
    523     }
    524 
    525     /** A JVMS 4.7.20 target_type kind. */
    526     public enum TargetType {
    527       CLASS_TYPE_PARAMETER(0x00),
    528       METHOD_TYPE_PARAMETER(0x01),
    529       SUPERTYPE(0x10),
    530       CLASS_TYPE_PARAMETER_BOUND(0x11),
    531       METHOD_TYPE_PARAMETER_BOUND(0x12),
    532       FIELD(0x13),
    533       METHOD_RETURN(0x14),
    534       METHOD_RECEIVER_PARAMETER(0x15),
    535       METHOD_FORMAL_PARAMETER(0x16),
    536       METHOD_THROWS(0x17);
    537 
    538       private final int tag;
    539 
    540       TargetType(int tag) {
    541         this.tag = tag;
    542       }
    543 
    544       public int tag() {
    545         return tag;
    546       }
    547     }
    548 
    549     /** A JVMS 4.7.20 target_info. */
    550     public abstract static class Target {
    551       /** Target info kind. */
    552       public enum Kind {
    553         TYPE_PARAMETER,
    554         SUPERTYPE,
    555         TYPE_PARAMETER_BOUND,
    556         EMPTY,
    557         FORMAL_PARAMETER,
    558         THROWS;
    559       }
    560 
    561       /** Returns the target info kind. */
    562       public abstract Kind kind();
    563     }
    564 
    565     /** A JVMS 4.7.20.1 type_parameter_target. */
    566     public static class TypeParameterTarget extends Target {
    567       private final int index;
    568 
    569       public TypeParameterTarget(int index) {
    570         this.index = index;
    571       }
    572 
    573       public int index() {
    574         return index;
    575       }
    576 
    577       @Override
    578       public Kind kind() {
    579         return Kind.TYPE_PARAMETER;
    580       }
    581     }
    582 
    583     /** A JVMS 4.7.20.1 supertype_target. */
    584     public static class SuperTypeTarget extends Target {
    585       private final int index;
    586 
    587       public SuperTypeTarget(int index) {
    588         this.index = index;
    589       }
    590 
    591       @Override
    592       public Kind kind() {
    593         return Kind.SUPERTYPE;
    594       }
    595 
    596       public int index() {
    597         return index;
    598       }
    599     }
    600 
    601     /** A JVMS 4.7.20.1 type_parameter_bound_target. */
    602     public static class TypeParameterBoundTarget extends Target {
    603       private final int typeParameterIndex;
    604       private final int boundIndex;
    605 
    606       public TypeParameterBoundTarget(int typeParameterIndex, int boundIndex) {
    607         this.typeParameterIndex = typeParameterIndex;
    608         this.boundIndex = boundIndex;
    609       }
    610 
    611       @Override
    612       public Kind kind() {
    613         return Kind.TYPE_PARAMETER_BOUND;
    614       }
    615 
    616       public int typeParameterIndex() {
    617         return typeParameterIndex;
    618       }
    619 
    620       public int boundIndex() {
    621         return boundIndex;
    622       }
    623     }
    624 
    625     /** A JVMS 4.7.20.1 empty_target. */
    626     public static final Target EMPTY_TARGET =
    627         new Target() {
    628           @Override
    629           public Kind kind() {
    630             return Kind.EMPTY;
    631           }
    632         };
    633 
    634     /** A JVMS 4.7.20.1 formal_parameter_target. */
    635     public static class FormalParameterTarget extends Target {
    636       private final int index;
    637 
    638       public FormalParameterTarget(int index) {
    639         this.index = index;
    640       }
    641 
    642       @Override
    643       public Kind kind() {
    644         return Kind.FORMAL_PARAMETER;
    645       }
    646 
    647       public int index() {
    648         return index;
    649       }
    650     }
    651 
    652     /** A JVMS 4.7.20.1 throws_target. */
    653     public static class ThrowsTarget extends Target {
    654       private final int index;
    655 
    656       public ThrowsTarget(int index) {
    657         this.index = index;
    658       }
    659 
    660       @Override
    661       public Kind kind() {
    662         return Kind.THROWS;
    663       }
    664 
    665       public int index() {
    666         return index;
    667       }
    668     }
    669 
    670     /**
    671      * A JVMS 4.7.20.2 type_path.
    672      *
    673      * <p>Represented as an immutable linked-list of nodes, which is built out by {@code Lower}
    674      * while recursively searching for type annotations to process.
    675      */
    676     public static class TypePath {
    677 
    678       /** The root type_path_kind, used for initialization. */
    679       public static TypePath root() {
    680         return new TypePath(null, null);
    681       }
    682 
    683       /** Adds an array type_path_kind entry. */
    684       public TypePath array() {
    685         return new TypePath(Kind.ARRAY, this);
    686       }
    687 
    688       /** Adds a nested type type_path_kind entry. */
    689       public TypePath nested() {
    690         return new TypePath(Kind.NESTED, this);
    691       }
    692 
    693       /** Adds a wildcard bound type_path_kind entry. */
    694       public TypePath wild() {
    695         return new TypePath(Kind.WILDCARD_BOUND, this);
    696       }
    697 
    698       /** Adds a type argument type_path_kind entry. */
    699       public TypePath typeArgument(int idx) {
    700         return new TypePath(idx, Kind.TYPE_ARGUMENT, this);
    701       }
    702 
    703       /** A type_path_kind. */
    704       enum Kind {
    705         ARRAY(0),
    706         NESTED(1),
    707         WILDCARD_BOUND(2),
    708         TYPE_ARGUMENT(3);
    709 
    710         final int tag;
    711 
    712         Kind(int tag) {
    713           this.tag = tag;
    714         }
    715       }
    716 
    717       private final TypePath parent;
    718       private final Kind kind;
    719       private final int index;
    720 
    721       private TypePath(Kind kind, TypePath parent) {
    722         // JVMS 4.7.20.2: type_argument_index is 0 if the bound kind is not TYPE_ARGUMENT
    723         this(0, kind, parent);
    724       }
    725 
    726       private TypePath(int index, Kind kind, TypePath parent) {
    727         this.index = index;
    728         this.kind = kind;
    729         this.parent = parent;
    730       }
    731 
    732       /** The type argument index; set only if the kind is {@code TYPE_ARGUMENT}. */
    733       public int typeArgumentIndex() {
    734         return index;
    735       }
    736 
    737       /** The JVMS 4.7.20.2-A serialized value of the type_path_kind. */
    738       public byte tag() {
    739         return (byte) kind.tag;
    740       }
    741 
    742       /** Returns a flattened view of the type path. */
    743       public ImmutableList<TypePath> flatten() {
    744         Deque<TypePath> flat = new ArrayDeque<>();
    745         for (TypePath curr = this; curr.kind != null; curr = curr.parent) {
    746           flat.addFirst(curr);
    747         }
    748         return ImmutableList.copyOf(flat);
    749       }
    750     }
    751   }
    752 }
    753