1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.experimental.bytecode; 25 26 import java.util.function.Consumer; 27 28 /** 29 * Base class builder. The base of higher level class builders. 30 * 31 * @param <S> the type of symbol representation 32 * @param <T> the type of type descriptors representation 33 * @param <C> the type of this builder 34 */ 35 public class ClassBuilder<S, T, C extends ClassBuilder<S, T, C>> 36 extends DeclBuilder<S, T, byte[], C> { 37 38 /** 39 * The helper to use to manipulate type descriptors. 40 */ 41 protected TypeHelper<S, T> typeHelper; 42 43 /** 44 * The symbol for the class being built. 45 */ 46 protected S thisClass; 47 48 /** 49 * The super-interfaces of the class being built.. 50 */ 51 protected GrowableByteBuffer interfaces = new GrowableByteBuffer(); 52 53 /** 54 * The fields of the class being built. 55 */ 56 protected GrowableByteBuffer fields = new GrowableByteBuffer(); 57 58 /** 59 * The methods of the class being built. 60 */ 61 protected GrowableByteBuffer methods = new GrowableByteBuffer(); 62 63 int majorVersion; 64 int minorVersion; 65 int flags; 66 int superclass; 67 int nmethods, nfields, ninterfaces; 68 69 /** 70 * Create a class builder. 71 * 72 * @param poolHelper the helper to build the constant pool 73 * @param typeHelper the helper to use to manipulate type descriptors 74 */ 75 public ClassBuilder(BytePoolHelper<S, T> poolHelper, TypeHelper<S, T> typeHelper) { 76 super(poolHelper, typeHelper); 77 this.typeHelper = typeHelper; 78 } 79 80 /** 81 * Set the minor class file version. 82 * 83 * @param minorVersion the minor version number 84 * @return this builder, for chained calls 85 */ 86 public C withMinorVersion(int minorVersion) { 87 this.minorVersion = minorVersion; 88 return thisBuilder(); 89 } 90 91 /** 92 * Set the major class file version. 93 * 94 * @param majorVersion the major version number 95 * @return this builder, for chained calls 96 */ 97 public C withMajorVersion(int majorVersion) { 98 this.majorVersion = majorVersion; 99 return thisBuilder(); 100 } 101 102 /** 103 * Set the class symbol 104 * 105 * @param thisClass the class symbol 106 * @return this builder, for chained calls 107 */ 108 public C withThisClass(S thisClass) { 109 this.thisClass = thisClass; 110 return thisBuilder(); 111 } 112 113 /** 114 * Set the class access flags 115 * 116 * @param flags an array of {@code Flag} 117 * @return this builder, for chained calls 118 */ 119 @Override 120 public C withFlags(Flag... flags) { 121 for (Flag f : flags) { 122 this.flags |= f.flag; 123 } 124 return thisBuilder(); 125 } 126 127 /** 128 * Set the superclass 129 * 130 * @param sup the superclass symbol 131 * @return this builder, for chained calls 132 */ 133 public C withSuperclass(S sup) { 134 this.superclass = poolHelper.putClass(sup); 135 return thisBuilder(); 136 } 137 138 /** 139 * Add a super interface. 140 * 141 * @param sup an interface symbol 142 * @return this builder, for chained calls 143 */ 144 public C withSuperinterface(S sup) { 145 this.interfaces.writeChar(poolHelper.putClass(sup)); 146 ninterfaces++; 147 return thisBuilder(); 148 } 149 150 /** 151 * Add a field. 152 * 153 * @param name the name of the field 154 * @param type the type descriptor of the field 155 * @return this builder, for chained calls 156 */ 157 public final C withField(CharSequence name, T type) { 158 return withField(name, type, FB -> { 159 }); 160 } 161 162 /** 163 * Add a field. 164 * 165 * @param name the name of the field 166 * @param type the type descriptor of the field 167 * @param fieldConfig access to the {@code FieldBuilder} to allow clients to 168 * adjust flags, annotations and bytecode attributes on the field declaration 169 * @return this builder, for chained calls 170 */ 171 public C withField(CharSequence name, T type, Consumer<? super FieldBuilder<S, T, byte[]>> fieldConfig) { 172 FieldBuilder<S, T, byte[]> F = new FieldBuilder<>(name, type, poolHelper, typeHelper); 173 fieldConfig.accept(F); 174 F.build(fields); 175 nfields++; 176 return thisBuilder(); 177 } 178 179 /** 180 * Add a method 181 * 182 * @param name the name of the method 183 * @param type the type descriptor of the method 184 * @return this builder, for chained calls 185 */ 186 public final C withMethod(CharSequence name, T type) { 187 return withMethod(name, type, MB -> { 188 }); 189 } 190 191 /** 192 * Add a method 193 * 194 * @param name the name of the method 195 * @param type the type descriptor of the method 196 * @param methodConfig access to the {@code MethodBuilder} to allow clients to 197 * adjust flags, annotations and bytecode attributes on the method declaration 198 * @return this builder, for chained calls 199 */ 200 public C withMethod(CharSequence name, T type, Consumer<? super MethodBuilder<S, T, byte[]>> methodConfig) { 201 MethodBuilder<S, T, byte[]> M = new MethodBuilder<>(thisClass, name, type, poolHelper, typeHelper); 202 methodConfig.accept(M); 203 M.build(methods); 204 nmethods++; 205 return thisBuilder(); 206 } 207 208 /** 209 * Build the constant pool into a byte array. 210 * 211 * @return a representation of this constant pool as a byte array 212 */ 213 @SuppressWarnings("unchecked") 214 public byte[] build() { 215 ((BytePoolHelper<S, T>)poolHelper).addAttributes(this); 216 addAnnotations(); 217 int thisClassIdx = poolHelper.putClass(thisClass); 218 byte[] poolBytes = poolHelper.entries(); 219 GrowableByteBuffer buf = new GrowableByteBuffer(); 220 buf.writeInt(0xCAFEBABE); 221 buf.writeChar(minorVersion); 222 buf.writeChar(majorVersion); 223 buf.writeChar(poolHelper.size() + 1); 224 buf.writeBytes(poolBytes); 225 buf.writeChar(flags); 226 buf.writeChar(thisClassIdx); 227 buf.writeChar(superclass); 228 buf.writeChar(ninterfaces); 229 if (ninterfaces > 0) { 230 buf.writeBytes(interfaces); 231 } 232 buf.writeChar(nfields); 233 buf.writeBytes(fields); 234 buf.writeChar(nmethods); 235 buf.writeBytes(methods); 236 buf.writeChar(nattrs); 237 buf.writeBytes(attributes); 238 return buf.bytes(); 239 } 240 }