1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.turbine.bytecode;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.google.turbine.model.Const.DoubleValue;
import com.google.turbine.model.Const.FloatValue;
import com.google.turbine.model.Const.IntValue;
import com.google.turbine.model.Const.LongValue;
import com.google.turbine.model.Const.StringValue;
import com.google.turbine.model.Const.Value;
import java.util.List;
/** Class file writing. */
public final class ClassWriter {
private static final int MAGIC = 0xcafebabe;
private static final int MINOR_VERSION = 0;
// use the lowest classfile version possible given the class file features
// TODO(cushon): is there a reason to support --release?
private static final int MAJOR_VERSION = 52;
private static final int MODULE_MAJOR_VERSION = 53;
/** Writes a {@link ClassFile} to bytecode. */
public static byte[] writeClass(ClassFile classfile) {
ConstantPool pool = new ConstantPool();
ByteArrayDataOutput output = ByteStreams.newDataOutput();
output.writeShort(classfile.access());
output.writeShort(pool.classInfo(classfile.name()));
output.writeShort(classfile.superName() != null ? pool.classInfo(classfile.superName()) : 0);
output.writeShort(classfile.interfaces().size());
for (String i : classfile.interfaces()) {
output.writeShort(pool.classInfo(i));
}
output.writeShort(classfile.fields().size());
for (ClassFile.FieldInfo f : classfile.fields()) {
writeField(pool, output, f);
}
output.writeShort(classfile.methods().size());
for (ClassFile.MethodInfo m : classfile.methods()) {
writeMethod(pool, output, m);
}
writeAttributes(pool, output, LowerAttributes.classAttributes(classfile));
return finishClass(pool, output, classfile);
}
private static void writeMethod(
ConstantPool pool, ByteArrayDataOutput output, ClassFile.MethodInfo method) {
output.writeShort(method.access());
output.writeShort(pool.utf8(method.name()));
output.writeShort(pool.utf8(method.descriptor()));
writeAttributes(pool, output, LowerAttributes.methodAttributes(method));
}
private static void writeField(
ConstantPool pool, ByteArrayDataOutput output, ClassFile.FieldInfo field) {
output.writeShort(field.access());
output.writeShort(pool.utf8(field.name()));
output.writeShort(pool.utf8(field.descriptor()));
writeAttributes(pool, output, LowerAttributes.fieldAttributes(field));
}
private static void writeAttributes(
ConstantPool pool, ByteArrayDataOutput body, List<Attribute> attributes) {
body.writeShort(attributes.size());
for (Attribute attribute : attributes) {
new AttributeWriter(pool, body).write(attribute);
}
}
static void writeConstantPool(ConstantPool constantPool, ByteArrayDataOutput output) {
output.writeShort(constantPool.nextEntry);
for (ConstantPool.Entry e : constantPool.constants()) {
output.writeByte(e.kind().tag());
Value value = e.value();
switch (e.kind()) {
case CLASS_INFO:
case STRING:
case MODULE:
case PACKAGE:
output.writeShort(((IntValue) value).value());
break;
case INTEGER:
output.writeInt(((IntValue) value).value());
break;
case DOUBLE:
output.writeDouble(((DoubleValue) value).value());
break;
case FLOAT:
output.writeFloat(((FloatValue) value).value());
break;
case LONG:
output.writeLong(((LongValue) value).value());
break;
case UTF8:
output.writeUTF(((StringValue) value).value());
break;
}
}
}
private static byte[] finishClass(
ConstantPool pool, ByteArrayDataOutput body, ClassFile classfile) {
ByteArrayDataOutput result = ByteStreams.newDataOutput();
result.writeInt(MAGIC);
result.writeShort(MINOR_VERSION);
result.writeShort(classfile.module() != null ? MODULE_MAJOR_VERSION : MAJOR_VERSION);
writeConstantPool(pool, result);
result.write(body.toByteArray());
return result.toByteArray();
}
private ClassWriter() {}
}
|