• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.bytecode;
18 
19 import com.google.common.io.ByteArrayDataOutput;
20 import com.google.common.io.ByteStreams;
21 import com.google.turbine.bytecode.Attribute.Annotations;
22 import com.google.turbine.bytecode.Attribute.ConstantValue;
23 import com.google.turbine.bytecode.Attribute.ExceptionsAttribute;
24 import com.google.turbine.bytecode.Attribute.InnerClasses;
25 import com.google.turbine.bytecode.Attribute.MethodParameters;
26 import com.google.turbine.bytecode.Attribute.Signature;
27 import com.google.turbine.bytecode.Attribute.TypeAnnotations;
28 import com.google.turbine.bytecode.ClassFile.AnnotationInfo;
29 import com.google.turbine.bytecode.ClassFile.MethodInfo.ParameterInfo;
30 import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo;
31 import com.google.turbine.model.Const;
32 import java.util.List;
33 
34 /** Writer {@link Attribute}s to bytecode. */
35 public class AttributeWriter {
36 
37   private final ConstantPool pool;
38   private final ByteArrayDataOutput output;
39 
AttributeWriter(ConstantPool pool, ByteArrayDataOutput output)40   public AttributeWriter(ConstantPool pool, ByteArrayDataOutput output) {
41     this.pool = pool;
42     this.output = output;
43   }
44 
45   /** Writes a single attribute. */
write(Attribute attribute)46   public void write(Attribute attribute) {
47     switch (attribute.kind()) {
48       case SIGNATURE:
49         writeSignatureAttribute((Signature) attribute);
50         break;
51       case EXCEPTIONS:
52         writeExceptionsAttribute((ExceptionsAttribute) attribute);
53         break;
54       case INNER_CLASSES:
55         writeInnerClasses((InnerClasses) attribute);
56         break;
57       case CONSTANT_VALUE:
58         writeConstantValue((ConstantValue) attribute);
59         break;
60       case RUNTIME_VISIBLE_ANNOTATIONS:
61       case RUNTIME_INVISIBLE_ANNOTATIONS:
62         writeAnnotation((Attribute.Annotations) attribute);
63         break;
64       case ANNOTATION_DEFAULT:
65         writeAnnotationDefault((Attribute.AnnotationDefault) attribute);
66         break;
67       case RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
68       case RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
69         writeParameterAnnotations((Attribute.ParameterAnnotations) attribute);
70         break;
71       case DEPRECATED:
72         writeDeprecated(attribute);
73         break;
74       case RUNTIME_INVISIBLE_TYPE_ANNOTATIONS:
75       case RUNTIME_VISIBLE_TYPE_ANNOTATIONS:
76         writeTypeAnnotation((Attribute.TypeAnnotations) attribute);
77         break;
78       case METHOD_PARAMETERS:
79         writeMethodParameters((Attribute.MethodParameters) attribute);
80         break;
81       default:
82         throw new AssertionError(attribute.kind());
83     }
84   }
85 
writeInnerClasses(InnerClasses attribute)86   private void writeInnerClasses(InnerClasses attribute) {
87     output.writeShort(pool.utf8(attribute.kind().signature()));
88     output.writeInt(attribute.inners.size() * 8 + 2);
89     output.writeShort(attribute.inners.size());
90     for (ClassFile.InnerClass inner : attribute.inners) {
91       output.writeShort(pool.classInfo(inner.innerClass()));
92       output.writeShort(pool.classInfo(inner.outerClass()));
93       output.writeShort(pool.utf8(inner.innerName()));
94       output.writeShort(inner.access());
95     }
96   }
97 
writeExceptionsAttribute(ExceptionsAttribute attribute)98   private void writeExceptionsAttribute(ExceptionsAttribute attribute) {
99     output.writeShort(pool.utf8(attribute.kind().signature()));
100     output.writeInt(2 + attribute.exceptions.size() * 2);
101     output.writeShort(attribute.exceptions.size());
102     for (String exception : attribute.exceptions) {
103       output.writeShort(pool.classInfo(exception));
104     }
105   }
106 
writeSignatureAttribute(Signature attribute)107   private void writeSignatureAttribute(Signature attribute) {
108     output.writeShort(pool.utf8(attribute.kind().signature()));
109     output.writeInt(2);
110     output.writeShort(pool.utf8(attribute.signature));
111   }
112 
writeConstantValue(ConstantValue attribute)113   public void writeConstantValue(ConstantValue attribute) {
114     output.writeShort(pool.utf8(attribute.kind().signature()));
115     output.writeInt(2);
116     Const.Value value = attribute.value;
117     switch (value.constantTypeKind()) {
118       case INT:
119       case CHAR:
120       case SHORT:
121       case BYTE:
122         output.writeShort(pool.integer(value.asInteger().value()));
123         break;
124       case LONG:
125         output.writeShort(pool.longInfo(value.asLong().value()));
126         break;
127       case DOUBLE:
128         output.writeShort(pool.doubleInfo(value.asDouble().value()));
129         break;
130       case FLOAT:
131         output.writeShort(pool.floatInfo(value.asFloat().value()));
132         break;
133       case BOOLEAN:
134         output.writeShort(pool.integer(value.asBoolean().value() ? 1 : 0));
135         break;
136       case STRING:
137         output.writeShort(pool.string(value.asString().value()));
138         break;
139       default:
140         throw new AssertionError(value.constantTypeKind());
141     }
142   }
143 
writeAnnotation(Annotations attribute)144   public void writeAnnotation(Annotations attribute) {
145     output.writeShort(pool.utf8(attribute.kind().signature()));
146     ByteArrayDataOutput tmp = ByteStreams.newDataOutput();
147     tmp.writeShort(attribute.annotations().size());
148     for (AnnotationInfo annotation : attribute.annotations()) {
149       new AnnotationWriter(pool, tmp).writeAnnotation(annotation);
150     }
151     byte[] data = tmp.toByteArray();
152     output.writeInt(data.length);
153     output.write(data);
154   }
155 
writeAnnotationDefault(Attribute.AnnotationDefault attribute)156   public void writeAnnotationDefault(Attribute.AnnotationDefault attribute) {
157     output.writeShort(pool.utf8(attribute.kind().signature()));
158     ByteArrayDataOutput tmp = ByteStreams.newDataOutput();
159     new AnnotationWriter(pool, tmp).writeElementValue(attribute.value());
160     byte[] data = tmp.toByteArray();
161     output.writeInt(data.length);
162     output.write(data);
163   }
164 
writeParameterAnnotations(Attribute.ParameterAnnotations attribute)165   public void writeParameterAnnotations(Attribute.ParameterAnnotations attribute) {
166     output.writeShort(pool.utf8(attribute.kind().signature()));
167     ByteArrayDataOutput tmp = ByteStreams.newDataOutput();
168     tmp.writeByte(attribute.annotations().size());
169     for (List<AnnotationInfo> parameterAnnotations : attribute.annotations()) {
170       tmp.writeShort(parameterAnnotations.size());
171       for (AnnotationInfo annotation : parameterAnnotations) {
172         new AnnotationWriter(pool, tmp).writeAnnotation(annotation);
173       }
174     }
175     byte[] data = tmp.toByteArray();
176     output.writeInt(data.length);
177     output.write(data);
178   }
179 
writeDeprecated(Attribute attribute)180   private void writeDeprecated(Attribute attribute) {
181     output.writeShort(pool.utf8(attribute.kind().signature()));
182     output.writeInt(0);
183   }
184 
writeTypeAnnotation(TypeAnnotations attribute)185   private void writeTypeAnnotation(TypeAnnotations attribute) {
186     output.writeShort(pool.utf8(attribute.kind().signature()));
187     ByteArrayDataOutput tmp = ByteStreams.newDataOutput();
188     tmp.writeShort(attribute.annotations().size());
189     for (TypeAnnotationInfo annotation : attribute.annotations()) {
190       new AnnotationWriter(pool, tmp).writeTypeAnnotation(annotation);
191     }
192     byte[] data = tmp.toByteArray();
193     output.writeInt(data.length);
194     output.write(data);
195   }
196 
writeMethodParameters(MethodParameters attribute)197   private void writeMethodParameters(MethodParameters attribute) {
198     output.writeShort(pool.utf8(attribute.kind().signature()));
199     output.writeInt(attribute.parameters().size() * 4 + 1);
200     output.writeByte(attribute.parameters().size());
201     for (ParameterInfo parameter : attribute.parameters()) {
202       output.writeShort(parameter.name() != null ? pool.utf8(parameter.name()) : 0);
203       output.writeShort(parameter.access());
204     }
205   }
206 }
207