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