test/jdk/lib/testlibrary/bytecode/jdk/experimental/bytecode/AnnotationsBuilder.java
author psandoz
Fri, 08 Sep 2017 10:46:46 -0700
changeset 48826 c4d9d1b08e2e
permissions -rw-r--r--
8186209: Tool support for ConstantDynamic 8186046: Minimal ConstantDynamic support 8190972: Ensure that AOT/Graal filters out class files containing CONSTANT_Dynamic ahead of full AOT support Reviewed-by: acorn, coleenp, kvn Contributed-by: lois.foltan@oracle.com, john.r.rose@oracle.com, paul.sandoz@oracle.com

/*
 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.experimental.bytecode;

import java.util.function.Consumer;
import java.util.function.ToIntBiFunction;

public class AnnotationsBuilder<S, T, E> extends AbstractBuilder<S, T, E, AnnotationsBuilder<S, T, E>> {

    GrowableByteBuffer annoAttribute;
    int nannos;

    AnnotationsBuilder(PoolHelper<S, T, E> poolHelper, TypeHelper<S, T> typeHelper) {
        super(poolHelper, typeHelper);
        this.annoAttribute = new GrowableByteBuffer();
        annoAttribute.writeChar(0);
    }

    public enum Kind {
        RUNTIME_VISIBLE,
        RUNTIME_INVISIBLE;
    }

    enum Tag {
        B('B'),
        C('C'),
        D('D'),
        F('F'),
        I('I'),
        J('J'),
        S('S'),
        Z('Z'),
        STRING('s'),
        ENUM('e'),
        CLASS('c'),
        ANNO('@'),
        ARRAY('[');

        char tagChar;

        Tag(char tagChar) {
            this.tagChar = tagChar;
        }
    }

    AnnotationsBuilder<S, T, E> withAnnotation(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
        annoAttribute.writeChar(poolHelper.putType(annoType));
        int offset = annoAttribute.offset;
        annoAttribute.writeChar(0);
        if (annotationBuilder != null) {
            AnnotationElementBuilder _builder = new AnnotationElementBuilder();
            int nelems = _builder.withElements(annotationBuilder);
            patchCharAt(offset, nelems);
        }
        nannos++;
        return this;
    }

    byte[] build() {
        patchCharAt(0, nannos);
        return annoAttribute.bytes();
    }

    private void patchCharAt(int offset, int newChar) {
        int prevOffset = annoAttribute.offset;
        try {
            annoAttribute.offset = offset;
            annoAttribute.writeChar(newChar);
        } finally {
            annoAttribute.offset = prevOffset;
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    static Consumer NO_BUILDER =
            new Consumer() {
                @Override
                public void accept(Object o) {
                    //do nothing
                }
            };

    public class AnnotationElementBuilder {

        int nelems;

        public AnnotationElementBuilder withString(String name, String s) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writeStringValue(s);
            return this;
        }

        private void writeStringValue(String s) {
            annoAttribute.writeByte(Tag.STRING.tagChar);
            annoAttribute.writeChar(poolHelper.putUtf8(s));
            nelems++;
        }

        public AnnotationElementBuilder withClass(String name, T s) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writeClassValue(s);
            return this;
        }

        private void writeClassValue(T s) {
            annoAttribute.writeByte(Tag.CLASS.tagChar);
            annoAttribute.writeChar(poolHelper.putType(s));
            nelems++;
        }

        public AnnotationElementBuilder withEnum(String name, T enumType, int constant) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writeEnumValue(enumType, constant);
            return this;
        }

        private void writeEnumValue(T enumType, int constant) {
            annoAttribute.writeByte(Tag.ENUM.tagChar);
            annoAttribute.writeChar(poolHelper.putType(enumType));
            annoAttribute.writeChar(constant);
            nelems++;
        }

        public AnnotationElementBuilder withAnnotation(String name, T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writeAnnotationValue(annoType, annotationBuilder);
            return this;
        }

        private void writeAnnotationValue(T annoType, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
            annoAttribute.writeByte(Tag.ANNO.tagChar);
            annoAttribute.writeChar(poolHelper.putType(annoType));
            int offset = annoAttribute.offset;
            annoAttribute.writeChar(0);
            int nelems = withNestedElements(annotationBuilder);
            patchCharAt(offset, nelems);
            this.nelems++;
        }

        public AnnotationElementBuilder withPrimitive(String name, char c) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt);
            return this;
        }

        public AnnotationElementBuilder withPrimitive(String name, short s) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt);
            return this;
        }

        public AnnotationElementBuilder withPrimitive(String name, byte b) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt);
            return this;
        }

        public AnnotationElementBuilder withPrimitive(String name, int i) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.I, i, PoolHelper::putInt);
            return this;
        }

        public AnnotationElementBuilder withPrimitive(String name, float f) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.F, f, PoolHelper::putFloat);
            return this;
        }

        public AnnotationElementBuilder withPrimitive(String name, long l) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.J, l, PoolHelper::putLong);
            return this;
        }

        public AnnotationElementBuilder withPrimitive(String name, double d) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.D, d, PoolHelper::putDouble);
            return this;
        }

        public AnnotationElementBuilder withPrimitive(String name, boolean b) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt);
            return this;
        }

        private <Z> void writePrimitiveValue(Tag tag, Z value, ToIntBiFunction<PoolHelper<S, T, E>, Z> poolFunc) {
            annoAttribute.writeByte(tag.tagChar);
            annoAttribute.writeChar(poolFunc.applyAsInt(poolHelper, value));
            nelems++;
        }

        AnnotationElementBuilder withStrings(String name, String... ss) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(ss.length);
            for (String s : ss) {
                writeStringValue(s);
            }
            return this;
        }

        @SuppressWarnings("unchecked")
        AnnotationElementBuilder withClasses(String name, T... cc) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(cc.length);
            for (T c : cc) {
                writeClassValue(c);
            }
            return this;
        }

        AnnotationElementBuilder withEnums(String name, T enumType, int... constants) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(constants.length);
            for (int c : constants) {
                writeEnumValue(enumType, c);
            }
            return this;
        }

        @SuppressWarnings("unchecked")
        public AnnotationElementBuilder withAnnotations(String name, T annoType, Consumer<? super AnnotationElementBuilder>... annotationBuilders) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(annotationBuilders.length);
            for (Consumer<? super AnnotationElementBuilder> annotationBuilder : annotationBuilders) {
                writeAnnotationValue(annoType, annotationBuilder);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, char... cc) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(cc.length);
            for (char c : cc) {
                writePrimitiveValue(Tag.C, (int)c, PoolHelper::putInt);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, short... ss) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(ss.length);
            for (short s : ss) {
                writePrimitiveValue(Tag.S, (int)s, PoolHelper::putInt);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, byte... bb) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(bb.length);
            for (byte b : bb) {
                writePrimitiveValue(Tag.B, (int)b, PoolHelper::putInt);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, int... ii) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(ii.length);
            for (int i : ii) {
                writePrimitiveValue(Tag.I, i,  PoolHelper::putInt);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, float... ff) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(ff.length);
            for (float f : ff) {
                writePrimitiveValue(Tag.F, f, PoolHelper::putFloat);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, long... ll) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(ll.length);
            for (long l : ll) {
                writePrimitiveValue(Tag.J, l, PoolHelper::putLong);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, double... dd) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(dd.length);
            for (double d : dd) {
                writePrimitiveValue(Tag.D, d, PoolHelper::putDouble);
            }
            return this;
        }

        public AnnotationElementBuilder withPrimitives(String name, boolean... bb) {
            annoAttribute.writeChar(poolHelper.putUtf8(name));
            annoAttribute.writeChar(bb.length);
            for (boolean b : bb) {
                writePrimitiveValue(Tag.Z, b ? 1 : 0, PoolHelper::putInt);
            }
            return this;
        }

        int withNestedElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) {
            return withElements(new AnnotationElementBuilder(), annotationBuilder);
        }

        int withElements(Consumer<? super AnnotationElementBuilder> annotationBuilder) {
            return withElements(this, annotationBuilder);
        }

        private int withElements(AnnotationElementBuilder builder, Consumer<? super AnnotationElementBuilder> annotationBuilder) {
            annotationBuilder.accept(builder);
            return builder.nelems;
        }
    }
}