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