1783f80f37ad70eba7fd4b5e11a34854724227bf6cushon/*
2783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * Copyright 2016 Google Inc. All Rights Reserved.
3783f80f37ad70eba7fd4b5e11a34854724227bf6cushon *
4783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * Licensed under the Apache License, Version 2.0 (the "License");
5783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * you may not use this file except in compliance with the License.
6783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * You may obtain a copy of the License at
7783f80f37ad70eba7fd4b5e11a34854724227bf6cushon *
8783f80f37ad70eba7fd4b5e11a34854724227bf6cushon *     http://www.apache.org/licenses/LICENSE-2.0
9783f80f37ad70eba7fd4b5e11a34854724227bf6cushon *
10783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * Unless required by applicable law or agreed to in writing, software
11783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * distributed under the License is distributed on an "AS IS" BASIS,
12783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * See the License for the specific language governing permissions and
14783f80f37ad70eba7fd4b5e11a34854724227bf6cushon * limitations under the License.
15783f80f37ad70eba7fd4b5e11a34854724227bf6cushon */
16783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
17783f80f37ad70eba7fd4b5e11a34854724227bf6cushonpackage com.google.turbine.bytecode;
18783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
19783f80f37ad70eba7fd4b5e11a34854724227bf6cushonimport com.google.common.io.ByteArrayDataOutput;
20783f80f37ad70eba7fd4b5e11a34854724227bf6cushonimport com.google.common.io.ByteStreams;
21bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushonimport com.google.turbine.model.Const.DoubleValue;
22bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushonimport com.google.turbine.model.Const.FloatValue;
23bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushonimport com.google.turbine.model.Const.IntValue;
24bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushonimport com.google.turbine.model.Const.LongValue;
25bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushonimport com.google.turbine.model.Const.StringValue;
26783f80f37ad70eba7fd4b5e11a34854724227bf6cushonimport com.google.turbine.model.Const.Value;
27783f80f37ad70eba7fd4b5e11a34854724227bf6cushonimport java.util.List;
28783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
29783f80f37ad70eba7fd4b5e11a34854724227bf6cushon/** Class file writing. */
30783f80f37ad70eba7fd4b5e11a34854724227bf6cushonpublic class ClassWriter {
31783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
32783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private static final int MAGIC = 0xcafebabe;
33783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private static final int MINOR_VERSION = 0;
34783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  // TODO(cushon): configuration?
35783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private static final int MAJOR_VERSION = 52;
36783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
37783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  /** Writes a {@link ClassFile} to bytecode. */
38783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  public static byte[] writeClass(ClassFile classfile) {
39783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    ConstantPool pool = new ConstantPool();
40783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    ByteArrayDataOutput output = ByteStreams.newDataOutput();
41783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(classfile.access());
42783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(pool.classInfo(classfile.name()));
43d8ea288afe5a7df01f74a0c5b55e489b0dc62349cushon    output.writeShort(classfile.superName() != null ? pool.classInfo(classfile.superName()) : 0);
44783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(classfile.interfaces().size());
45783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    for (String i : classfile.interfaces()) {
46783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      output.writeShort(pool.classInfo(i));
47783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    }
48783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(classfile.fields().size());
49783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    for (ClassFile.FieldInfo f : classfile.fields()) {
50783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      writeField(pool, output, f);
51783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    }
52783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(classfile.methods().size());
53783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    for (ClassFile.MethodInfo m : classfile.methods()) {
54783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      writeMethod(pool, output, m);
55783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    }
56783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    writeAttributes(pool, output, LowerAttributes.classAttributes(classfile));
57783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    return finishClass(pool, output);
58783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  }
59783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
60783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private static void writeMethod(
61783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      ConstantPool pool, ByteArrayDataOutput output, ClassFile.MethodInfo method) {
62783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(method.access());
63783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(pool.utf8(method.name()));
64783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(pool.utf8(method.descriptor()));
65783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    writeAttributes(pool, output, LowerAttributes.methodAttributes(method));
66783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  }
67783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
68783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private static void writeField(
69783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      ConstantPool pool, ByteArrayDataOutput output, ClassFile.FieldInfo field) {
70783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(field.access());
71783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(pool.utf8(field.name()));
72783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(pool.utf8(field.descriptor()));
73783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    writeAttributes(pool, output, LowerAttributes.fieldAttributes(field));
74783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  }
75783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
76783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private static void writeAttributes(
77783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      ConstantPool pool, ByteArrayDataOutput body, List<Attribute> attributes) {
78783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    body.writeShort(attributes.size());
79783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    for (Attribute attribute : attributes) {
80783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      new AttributeWriter(pool, body).write(attribute);
81783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    }
82783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  }
83783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
84783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  static void writeConstantPool(ConstantPool constantPool, ByteArrayDataOutput output) {
85783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    output.writeShort(constantPool.nextEntry);
86783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    for (ConstantPool.Entry e : constantPool.constants()) {
87783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      output.writeByte(e.kind().tag());
88783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      Value value = e.value();
8933b30eb88e4724f61d7ea86b0a6564cb702e6615cushon      switch (e.kind()) {
9033b30eb88e4724f61d7ea86b0a6564cb702e6615cushon        case CLASS_INFO:
91783f80f37ad70eba7fd4b5e11a34854724227bf6cushon        case STRING:
9233b30eb88e4724f61d7ea86b0a6564cb702e6615cushon          output.writeShort(((IntValue) value).value());
93783f80f37ad70eba7fd4b5e11a34854724227bf6cushon          break;
9433b30eb88e4724f61d7ea86b0a6564cb702e6615cushon        case INTEGER:
95bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushon          output.writeInt(((IntValue) value).value());
96bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushon          break;
9733b30eb88e4724f61d7ea86b0a6564cb702e6615cushon        case DOUBLE:
9833b30eb88e4724f61d7ea86b0a6564cb702e6615cushon          output.writeDouble(((DoubleValue) value).value());
99bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushon          break;
100bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushon        case FLOAT:
101bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushon          output.writeFloat(((FloatValue) value).value());
102bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushon          break;
10333b30eb88e4724f61d7ea86b0a6564cb702e6615cushon        case LONG:
10433b30eb88e4724f61d7ea86b0a6564cb702e6615cushon          output.writeLong(((LongValue) value).value());
10533b30eb88e4724f61d7ea86b0a6564cb702e6615cushon          break;
10633b30eb88e4724f61d7ea86b0a6564cb702e6615cushon        case UTF8:
10733b30eb88e4724f61d7ea86b0a6564cb702e6615cushon          output.writeUTF(((StringValue) value).value());
108bd2b29bb7fd05aed8481ef8342c09c4e88492c88cushon          break;
109783f80f37ad70eba7fd4b5e11a34854724227bf6cushon        default:
11033b30eb88e4724f61d7ea86b0a6564cb702e6615cushon          throw new AssertionError(e.kind());
111783f80f37ad70eba7fd4b5e11a34854724227bf6cushon      }
112783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    }
113783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  }
114783f80f37ad70eba7fd4b5e11a34854724227bf6cushon
115783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  private static byte[] finishClass(ConstantPool pool, ByteArrayDataOutput body) {
116783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    ByteArrayDataOutput result = ByteStreams.newDataOutput();
117783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    result.writeInt(MAGIC);
118783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    result.writeShort(MINOR_VERSION);
119783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    result.writeShort(MAJOR_VERSION);
120783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    writeConstantPool(pool, result);
121783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    result.write(body.toByteArray());
122783f80f37ad70eba7fd4b5e11a34854724227bf6cushon    return result.toByteArray();
123783f80f37ad70eba7fd4b5e11a34854724227bf6cushon  }
124783f80f37ad70eba7fd4b5e11a34854724227bf6cushon}
125