ClassWriter.java revision bd2b29bb7fd05aed8481ef8342c09c4e88492c88
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 17package com.google.turbine.bytecode; 18 19import com.google.common.io.ByteArrayDataOutput; 20import com.google.common.io.ByteStreams; 21import com.google.turbine.model.Const.DoubleValue; 22import com.google.turbine.model.Const.FloatValue; 23import com.google.turbine.model.Const.IntValue; 24import com.google.turbine.model.Const.LongValue; 25import com.google.turbine.model.Const.ShortValue; 26import com.google.turbine.model.Const.StringValue; 27import com.google.turbine.model.Const.Value; 28import java.util.List; 29 30/** Class file writing. */ 31public class ClassWriter { 32 33 private static final int MAGIC = 0xcafebabe; 34 private static final int MINOR_VERSION = 0; 35 // TODO(cushon): configuration? 36 private static final int MAJOR_VERSION = 52; 37 38 /** Writes a {@link ClassFile} to bytecode. */ 39 public static byte[] writeClass(ClassFile classfile) { 40 ConstantPool pool = new ConstantPool(); 41 ByteArrayDataOutput output = ByteStreams.newDataOutput(); 42 output.writeShort(classfile.access()); 43 output.writeShort(pool.classInfo(classfile.name())); 44 output.writeShort(pool.classInfo(classfile.superName())); 45 output.writeShort(classfile.interfaces().size()); 46 for (String i : classfile.interfaces()) { 47 output.writeShort(pool.classInfo(i)); 48 } 49 output.writeShort(classfile.fields().size()); 50 for (ClassFile.FieldInfo f : classfile.fields()) { 51 writeField(pool, output, f); 52 } 53 output.writeShort(classfile.methods().size()); 54 for (ClassFile.MethodInfo m : classfile.methods()) { 55 writeMethod(pool, output, m); 56 } 57 writeAttributes(pool, output, LowerAttributes.classAttributes(classfile)); 58 return finishClass(pool, output); 59 } 60 61 private static void writeMethod( 62 ConstantPool pool, ByteArrayDataOutput output, ClassFile.MethodInfo method) { 63 output.writeShort(method.access()); 64 output.writeShort(pool.utf8(method.name())); 65 output.writeShort(pool.utf8(method.descriptor())); 66 writeAttributes(pool, output, LowerAttributes.methodAttributes(method)); 67 } 68 69 private static void writeField( 70 ConstantPool pool, ByteArrayDataOutput output, ClassFile.FieldInfo field) { 71 output.writeShort(field.access()); 72 output.writeShort(pool.utf8(field.name())); 73 output.writeShort(pool.utf8(field.descriptor())); 74 writeAttributes(pool, output, LowerAttributes.fieldAttributes(field)); 75 } 76 77 private static void writeAttributes( 78 ConstantPool pool, ByteArrayDataOutput body, List<Attribute> attributes) { 79 body.writeShort(attributes.size()); 80 for (Attribute attribute : attributes) { 81 new AttributeWriter(pool, body).write(attribute); 82 } 83 } 84 85 static void writeConstantPool(ConstantPool constantPool, ByteArrayDataOutput output) { 86 output.writeShort(constantPool.nextEntry); 87 for (ConstantPool.Entry e : constantPool.constants()) { 88 output.writeByte(e.kind().tag()); 89 Value value = e.value(); 90 switch (value.constantTypeKind()) { 91 case STRING: 92 output.writeUTF(((StringValue) value).value()); 93 break; 94 case SHORT: 95 output.writeShort(((ShortValue) value).value()); 96 break; 97 case INT: 98 output.writeInt(((IntValue) value).value()); 99 break; 100 case LONG: 101 output.writeLong(((LongValue) value).value()); 102 break; 103 case FLOAT: 104 output.writeFloat(((FloatValue) value).value()); 105 break; 106 case DOUBLE: 107 output.writeDouble(((DoubleValue) value).value()); 108 break; 109 default: 110 throw new AssertionError(value.constantTypeKind()); 111 } 112 } 113 } 114 115 private static byte[] finishClass(ConstantPool pool, ByteArrayDataOutput body) { 116 ByteArrayDataOutput result = ByteStreams.newDataOutput(); 117 result.writeInt(MAGIC); 118 result.writeShort(MINOR_VERSION); 119 result.writeShort(MAJOR_VERSION); 120 writeConstantPool(pool, result); 121 result.write(body.toByteArray()); 122 return result.toByteArray(); 123 } 124} 125