1 /*
   2  * Copyright (c) 2016, 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 jdk.experimental.bytecode.CodeBuilder.JumpMode;
  29 
  30 import java.util.Iterator;
  31 import java.util.function.Consumer;
  32 import java.util.function.Function;
  33 
  34 public class MethodBuilder<S, T, E> extends MemberBuilder<S, T, E, MethodBuilder<S, T, E>> {
  35 
  36     S thisClass;
  37     ParameterAnnotationsBuilder runtimeVisibleParameterAnnotations;
  38     ParameterAnnotationsBuilder runtimeInvisibleParameterAnnotations;
  39 
  40     public MethodBuilder(S thisClass, CharSequence name, T type, PoolHelper<S, T, E> pool, TypeHelper<S, T> typeHelper) {
  41         super(name, type, pool, typeHelper);
  42         this.thisClass = thisClass;
  43     }
  44 
  45     public <C extends CodeBuilder<S, T, E, ?>> MethodBuilder<S, T, E> withCode(Function<? super MethodBuilder<S, T, E>, ? extends C> func,
  46                                                                                Consumer<? super C> code) {
  47         C codeBuilder = func.apply(this);
  48         int start = attributes.offset;
  49         try {
  50             code.accept(codeBuilder);
  51         } catch (MacroCodeBuilder.WideJumpException ex) {
  52             //wide jumps! Redo the code
  53             ((MacroCodeBuilder<S, T, E, ?>) codeBuilder).jumpMode = JumpMode.WIDE;
  54             ((MacroCodeBuilder<S, T, E, ?>) codeBuilder).clear();
  55             code.accept(codeBuilder);
  56         }
  57 
  58         attributes.writeChar(poolHelper.putUtf8("Code"));
  59         attributes.writeInt(0);
  60         codeBuilder.build(attributes);
  61         int length = attributes.offset - start;
  62         //avoid using lambda here
  63         int prevOffset = attributes.offset;
  64         try {
  65             attributes.offset = start + 2;
  66             attributes.writeInt(length - 6);
  67         } finally {
  68             attributes.offset = prevOffset;
  69         }
  70         nattrs++;
  71         return this;
  72     }
  73 
  74     public MethodBuilder<S, T, E> withCode(Consumer<? super CodeBuilder<S, T, E, ?>> code) {
  75         return withCode(CodeBuilder::new, code);
  76     }
  77 
  78     @SuppressWarnings({"varargs", "unchecked"})
  79     public MethodBuilder<S, T, E> withExceptions(S... exceptions) {
  80         attributes.writeChar(poolHelper.putUtf8("Exceptions"));
  81         attributes.writeInt(2 + (2 * exceptions.length));
  82         attributes.writeChar(exceptions.length);
  83         for (S exception : exceptions) {
  84             attributes.writeChar(poolHelper.putClass(exception));
  85         }
  86         nattrs++;
  87         return this;
  88     }
  89 
  90     public MethodBuilder<S, T, E> withParameterAnnotation(AnnotationsBuilder.Kind kind, int nparam, T annoType) {
  91         getParameterAnnotations(kind).builders[nparam].withAnnotation(annoType, null);
  92         return this;
  93     }
  94 
  95     public MethodBuilder<S, T, E> withParameterAnnotation(AnnotationsBuilder.Kind kind, int nparam, T annoType, Consumer<? super AnnotationsBuilder<S, T, E>.AnnotationElementBuilder> annotations) {
  96         getParameterAnnotations(kind).builders[nparam].withAnnotation(annoType, annotations);
  97         return this;
  98     }
  99 
 100     private ParameterAnnotationsBuilder getParameterAnnotations(AnnotationsBuilder.Kind kind) {
 101         switch (kind) {
 102             case RUNTIME_INVISIBLE:
 103                 if (runtimeInvisibleParameterAnnotations == null) {
 104                     runtimeInvisibleParameterAnnotations = new ParameterAnnotationsBuilder();
 105                 }
 106                 return runtimeInvisibleParameterAnnotations;
 107             case RUNTIME_VISIBLE:
 108                 if (runtimeVisibleParameterAnnotations == null) {
 109                     runtimeVisibleParameterAnnotations = new ParameterAnnotationsBuilder();
 110                 }
 111                 return runtimeVisibleParameterAnnotations;
 112         }
 113         throw new IllegalStateException();
 114     }
 115 
 116     class ParameterAnnotationsBuilder {
 117 
 118         GrowableByteBuffer parameterAnnos = new GrowableByteBuffer();
 119 
 120         @SuppressWarnings({"unchecked", "rawtypes"})
 121         AnnotationsBuilder<S, T, E>[] builders = new AnnotationsBuilder[nparams()];
 122 
 123         ParameterAnnotationsBuilder() {
 124             for (int i = 0; i < builders.length; i++) {
 125                 builders[i] = new AnnotationsBuilder<>(poolHelper, typeHelper);
 126             }
 127         }
 128 
 129         byte[] build() {
 130             parameterAnnos.writeByte(builders.length);
 131             for (AnnotationsBuilder<S, T, E> builder : builders) {
 132                 parameterAnnos.writeBytes(builder.build());
 133             }
 134             return parameterAnnos.bytes();
 135         }
 136 
 137         int nparams() {
 138             Iterator<T> paramsIt = typeHelper.parameterTypes(desc);
 139             int nparams = 0;
 140             while (paramsIt.hasNext()) {
 141                 paramsIt.next();
 142                 nparams++;
 143             }
 144             return nparams;
 145         }
 146     }
 147 
 148     @Override
 149     void addAnnotations() {
 150         super.addAnnotations();
 151         if (runtimeInvisibleParameterAnnotations != null) {
 152             withAttribute("RuntimeInvisibleParameterAnnotations", runtimeInvisibleParameterAnnotations.build());
 153         }
 154         if (runtimeVisibleParameterAnnotations != null) {
 155             withAttribute("RuntimeVisibleParameterAnnotations", runtimeVisibleParameterAnnotations.build());
 156         }
 157     }
 158 }