blob: ee5945808f342c23c629b825235dde74247206f4 [file] [log] [blame]
/*
* 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 jdk.experimental.bytecode.CodeBuilder.JumpMode;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Function;
public class MethodBuilder<S, T, E> extends MemberBuilder<S, T, E, MethodBuilder<S, T, E>> {
S thisClass;
ParameterAnnotationsBuilder runtimeVisibleParameterAnnotations;
ParameterAnnotationsBuilder runtimeInvisibleParameterAnnotations;
public MethodBuilder(S thisClass, CharSequence name, T type, PoolHelper<S, T, E> pool, TypeHelper<S, T> typeHelper) {
super(name, type, pool, typeHelper);
this.thisClass = thisClass;
}
public <C extends CodeBuilder<S, T, E, ?>> MethodBuilder<S, T, E> withCode(Function<? super MethodBuilder<S, T, E>, ? extends C> func,
Consumer<? super C> code) {
C codeBuilder = func.apply(this);
int start = attributes.offset;
try {
code.accept(codeBuilder);
} catch (MacroCodeBuilder.WideJumpException ex) {
//wide jumps! Redo the code
((MacroCodeBuilder<S, T, E, ?>) codeBuilder).jumpMode = JumpMode.WIDE;
((MacroCodeBuilder<S, T, E, ?>) codeBuilder).clear();
code.accept(codeBuilder);
}
attributes.writeChar(poolHelper.putUtf8("Code"));
attributes.writeInt(0);
codeBuilder.build(attributes);
int length = attributes.offset - start;
//avoid using lambda here
int prevOffset = attributes.offset;
try {
attributes.offset = start + 2;
attributes.writeInt(length - 6);
} finally {
attributes.offset = prevOffset;
}
nattrs++;
return this;
}
public MethodBuilder<S, T, E> withCode(Consumer<? super CodeBuilder<S, T, E, ?>> code) {
return withCode(CodeBuilder::new, code);
}
@SuppressWarnings({"varargs", "unchecked"})
public MethodBuilder<S, T, E> withExceptions(S... exceptions) {
attributes.writeChar(poolHelper.putUtf8("Exceptions"));
attributes.writeInt(2 + (2 * exceptions.length));
attributes.writeChar(exceptions.length);
for (S exception : exceptions) {
attributes.writeChar(poolHelper.putClass(exception));
}
nattrs++;
return this;
}
public MethodBuilder<S, T, E> withParameterAnnotation(AnnotationsBuilder.Kind kind, int nparam, T annoType) {
getParameterAnnotations(kind).builders[nparam].withAnnotation(annoType, null);
return this;
}
public MethodBuilder<S, T, E> withParameterAnnotation(AnnotationsBuilder.Kind kind, int nparam, T annoType, Consumer<? super AnnotationsBuilder<S, T, E>.AnnotationElementBuilder> annotations) {
getParameterAnnotations(kind).builders[nparam].withAnnotation(annoType, annotations);
return this;
}
private ParameterAnnotationsBuilder getParameterAnnotations(AnnotationsBuilder.Kind kind) {
switch (kind) {
case RUNTIME_INVISIBLE:
if (runtimeInvisibleParameterAnnotations == null) {
runtimeInvisibleParameterAnnotations = new ParameterAnnotationsBuilder();
}
return runtimeInvisibleParameterAnnotations;
case RUNTIME_VISIBLE:
if (runtimeVisibleParameterAnnotations == null) {
runtimeVisibleParameterAnnotations = new ParameterAnnotationsBuilder();
}
return runtimeVisibleParameterAnnotations;
}
throw new IllegalStateException();
}
class ParameterAnnotationsBuilder {
GrowableByteBuffer parameterAnnos = new GrowableByteBuffer();
@SuppressWarnings({"unchecked", "rawtypes"})
AnnotationsBuilder<S, T, E>[] builders = new AnnotationsBuilder[nparams()];
ParameterAnnotationsBuilder() {
for (int i = 0; i < builders.length; i++) {
builders[i] = new AnnotationsBuilder<>(poolHelper, typeHelper);
}
}
byte[] build() {
parameterAnnos.writeByte(builders.length);
for (AnnotationsBuilder<S, T, E> builder : builders) {
parameterAnnos.writeBytes(builder.build());
}
return parameterAnnos.bytes();
}
int nparams() {
Iterator<T> paramsIt = typeHelper.parameterTypes(desc);
int nparams = 0;
while (paramsIt.hasNext()) {
paramsIt.next();
nparams++;
}
return nparams;
}
}
@Override
void addAnnotations() {
super.addAnnotations();
if (runtimeInvisibleParameterAnnotations != null) {
withAttribute("RuntimeInvisibleParameterAnnotations", runtimeInvisibleParameterAnnotations.build());
}
if (runtimeVisibleParameterAnnotations != null) {
withAttribute("RuntimeVisibleParameterAnnotations", runtimeVisibleParameterAnnotations.build());
}
}
}